Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.impl / src / main / java / org / gvsig / fmap / dal / feature / impl / DefaultFeatureSelection.java @ 44097

History | View | Annotate | Download (24.3 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 3 of the License, or (at your option) any later
9
 * version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.fmap.dal.feature.impl;
24

    
25
import java.util.ArrayList;
26
import java.util.HashMap;
27
import java.util.Iterator;
28
import java.util.List;
29
import java.util.Map;
30
import java.util.Map.Entry;
31

    
32
import org.gvsig.fmap.dal.DataStoreNotification;
33
import org.gvsig.fmap.dal.exception.DataException;
34
import org.gvsig.fmap.dal.exception.DataRuntimeException;
35
import org.gvsig.fmap.dal.feature.EditableFeature;
36
import org.gvsig.fmap.dal.feature.Feature;
37
import org.gvsig.fmap.dal.feature.FeatureReference;
38
import org.gvsig.fmap.dal.feature.FeatureSelection;
39
import org.gvsig.fmap.dal.feature.FeatureSet;
40
import org.gvsig.fmap.dal.feature.FeatureStore;
41
import org.gvsig.fmap.dal.feature.FeatureType;
42
import org.gvsig.fmap.dal.feature.exception.ReversedSelectionIteratorException;
43
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection.SelectionData;
44
import org.gvsig.fmap.dal.feature.impl.featureset.AbstractFeatureSet;
45
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
46
import org.gvsig.tools.ToolsLocator;
47
import org.gvsig.tools.dispose.DisposableIterator;
48
import org.gvsig.tools.dispose.DisposeUtils;
49
import org.gvsig.tools.dynobject.DynStruct;
50
import org.gvsig.tools.exception.BaseException;
51
import org.gvsig.tools.observer.Observable;
52
import org.gvsig.tools.observer.Observer;
53
import org.gvsig.tools.persistence.PersistenceManager;
54
import org.gvsig.tools.persistence.PersistentState;
55
import org.gvsig.tools.persistence.exception.PersistenceException;
56
import org.gvsig.tools.visitor.Visitor;
57
import org.slf4j.Logger;
58
import org.slf4j.LoggerFactory;
59

    
60
/**
61
 * Default implementation of the FeatureSelection interface. Internally, only
62
 * FeatureReference values are stored.
63
 *
64
 * This implementation performs better if used with the selection related
65
 * methods: select, deselect and isSelected ones.
66
 *
67
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
68
 */
69
public class DefaultFeatureSelection extends AbstractFeatureSet
70
        implements FeatureSelection {
71

    
72
    public class RemoveFromFeatureSelectionException extends DataRuntimeException {
73

    
74
        /**
75
         *
76
         */
77
        private static final long serialVersionUID = 2636692469445838928L;
78
        private final static String MESSAGE_FORMAT = "Can't remove feature from reversed selection.";
79
        private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
80

    
81
        public RemoveFromFeatureSelectionException(Throwable cause) {
82
            super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
83
            //setValue("store", store);
84
        }
85
    }
86

    
87
    /**
88
     * Facade over a Iterator of FeatureReferences, to return Features instead.
89
     *
90
     * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
91
     */
92
    private class FeatureIteratorFacade implements DisposableIterator {
93

    
94
        private final Logger LOGGER = LoggerFactory
95
                .getLogger(FeatureIteratorFacade.class);
96

    
97
        private java.util.Iterator refIterator;
98

    
99
        private FeatureStore featureStore;
100
        private Feature currentFeature = null;
101

    
102
        public FeatureIteratorFacade(java.util.Iterator iter,
103
                FeatureStore featureStore) {
104
            this.refIterator = iter;
105
            this.featureStore = featureStore;
106
        }
107

    
108
        @Override
109
        public boolean hasNext() {
110
            return refIterator.hasNext();
111
        }
112

    
113
        @Override
114
        public Object next() {
115
            FeatureReference ref = nextFeatureReference();
116
            try {
117
                currentFeature = featureStore.getFeatureByReference(ref);
118
                return currentFeature;
119
            } catch (DataException ex) {
120
                LOGGER.error(
121
                        "Error loading the Feature with FeatureReference: "
122
                        + ref, ex);
123
                return null;
124
            }
125
        }
126

    
127
        /**
128
         * Returns the next FeatureReference.
129
         *
130
         * @return the next FeatureReference
131
         */
132
        public FeatureReference nextFeatureReference() {
133
            return (FeatureReference) refIterator.next();
134
        }
135

    
136
        @Override
137
        public void remove() {
138
            try {
139
                featureStore.delete(currentFeature);
140
                refIterator.remove();
141
            } catch (DataException e) {
142
                throw new RemoveFromFeatureSelectionException(e);
143
            }
144
        }
145

    
146
        public class RemoveFromFeatureSelectionException extends DataRuntimeException {
147

    
148
            /**
149
             *
150
             */
151
            private static final long serialVersionUID = 2636692469445838928L;
152
            private final static String MESSAGE_FORMAT = "Can't remove feature from selection.";
153
            private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
154

    
155
            public RemoveFromFeatureSelectionException(Throwable cause) {
156
                super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
157
                //setValue("store", store);
158
            }
159
        }
160

    
161
        @Override
162
        public void dispose() {
163
            if (refIterator instanceof DisposableIterator) {
164
                ((DisposableIterator) refIterator).dispose();
165
            }
166
            refIterator = null;
167
            featureStore = null;
168
        }
169
    }
170

    
171
    /**
172
     * Facade over a Iterator of FeatureReferences, to return Features instead,
173
     * when the Selection is reversed
174
     *
175
     * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
176
     */
177
    private class ReversedFeatureIteratorFacade implements DisposableIterator {
178

    
179
        private SelectionData selectionData;
180

    
181
        private DisposableIterator iterator;
182

    
183
        private Feature nextFeature = null;
184
        private Feature currentFeature = null;
185

    
186
        private FeatureSet featureSet;
187

    
188
        public ReversedFeatureIteratorFacade(SelectionData selectionData,
189
                FeatureStore featureStore, boolean fastIterator) {
190
            this.selectionData = selectionData;
191

    
192
            // Load a Set with all the store features
193
            try {
194
                featureSet = featureStore.getFeatureSet();
195
                //if (fastIterator) {
196
                iterator = featureSet.fastIterator();
197
//                                } else {
198
//                                        iterator = featureSet.iterator();
199
//                                }
200
            } catch (DataException ex) {
201
                throw new ReversedSelectionIteratorException(ex);
202
            }
203

    
204
            // Filter the features not selected and position in the next
205
            // selected feature
206
            positionInNextElement();
207
        }
208

    
209
        @Override
210
        public boolean hasNext() {
211
            return nextFeature != null;
212
        }
213

    
214
        @Override
215
        public Object next() {
216
            featureIterators.remove(currentFeature);
217
            currentFeature = nextFeature.getCopy();
218
            featureIterators.put(currentFeature, this);
219
            positionInNextElement();
220
            return currentFeature;
221
        }
222

    
223
        @Override
224
        public void remove() {
225
            try {
226
                featureSet.delete(currentFeature);
227
            } catch (DataException e) {
228
                throw new RemoveFromFeatureSelectionException(e);
229

    
230
            }
231
        }
232

    
233
        private void positionInNextElement() {
234
            nextFeature = null;
235
            while (iterator.hasNext()) {
236
                nextFeature = (Feature) iterator.next();
237
                if (selectionData.contains(nextFeature.getReference())) {
238
                    nextFeature = null;
239
                } else {
240
                    break;
241
                }
242
            }
243
        }
244

    
245
        @Override
246
        public void dispose() {
247
            this.featureSet.dispose();
248
            this.iterator.dispose();
249
            this.selectionData = null;
250
            this.nextFeature = null;
251
        }
252
    }
253

    
254
    private Map featureTypeCounts = new HashMap(1);
255
    private final Map<Feature, Iterator> featureIterators = new HashMap<>();
256
    private final DefaultFeatureReferenceSelection featureReferenceSelection;
257

    
258
    /**
259
     * Creates a DefaultFeatureSelection, with a FeatureStore.
260
     *
261
     * @param featureStore the FeatureStore to load Features from
262
     * @throws DataException if there is an error while getting the total number
263
     * of Features of the Store.
264
     * @see AbstractSetBasedDataSelection#DefaultSelection(int)
265
     */
266
    public DefaultFeatureSelection(DefaultFeatureStore featureStore)
267
            throws DataException {
268
        this.featureReferenceSelection = new DefaultFeatureReferenceSelection(featureStore);
269
    }
270

    
271
    /**
272
     * Creates a new Selection with the total size of Features from which the
273
     * selection will be performed.
274
     *
275
     * @param featureStore the FeatureStore of the selected FeatureReferences
276
     * @param helper to get some information of the Store
277
     * @throws DataException if there is an error while getting the total number
278
     * of Features of the Store.
279
     */
280
    public DefaultFeatureSelection(FeatureStore featureStore,
281
            FeatureSelectionHelper helper) throws DataException {
282
        this.featureReferenceSelection = new DefaultFeatureReferenceSelection(featureStore, helper);
283
    }
284

    
285
    /**
286
     * Constructor used by the persistence manager. Don't use directly. After to
287
     * invoke this method, the persistence manager calls the the method
288
     * {@link #loadFromState(PersistentState)} to set the values of the internal
289
     * attributes that this class needs to work.
290
     */
291
    public DefaultFeatureSelection() {
292
        this.featureReferenceSelection = new DefaultFeatureReferenceSelection();
293
    }
294

    
295
    @Override
296
    public FeatureStore getFeatureStore() {
297
        return this.featureReferenceSelection.getFeatureStore();
298
    }
299

    
300
    private void notifyObservers(String notificationType) {
301
        this.featureReferenceSelection.notifyObservers(notificationType);
302
    }
303

    
304
    public FeatureCommandsStack getCommands() {
305
        return this.featureReferenceSelection.getCommands();
306
    }
307

    
308
    @Override
309
    public void enableNotifications() {
310
        this.featureReferenceSelection.enableNotifications();
311
    }
312

    
313
    @Override
314
    public void disableNotifications() {
315
        this.featureReferenceSelection.disableNotifications();
316
    }
317

    
318
    public boolean isReversed() {
319
        return this.featureReferenceSelection.isReversed();
320
    }
321

    
322
    @Override
323
    public long getSelectedCount() {
324
        return this.featureReferenceSelection.getSelectedCount();
325
    }
326

    
327
    public DefaultFeatureReferenceSelection.SelectionData getData() {
328
        return this.featureReferenceSelection.getData();
329
    }
330

    
331
    @Override
332
    public boolean select(FeatureReference reference) {
333
        return this.featureReferenceSelection.select(reference);
334
    }
335

    
336
    public boolean select(FeatureReference reference, boolean undoable) {
337
        return this.featureReferenceSelection.select(reference, undoable);
338
    }
339

    
340
    @Override
341
    public boolean deselect(FeatureReference reference) {
342
        return this.featureReferenceSelection.deselect(reference);
343
    }
344

    
345
    public boolean deselect(FeatureReference reference, boolean undoable) {
346
        return this.featureReferenceSelection.deselect(reference, undoable);
347
    }
348

    
349
    @Override
350
    public Iterator referenceIterator() {
351
        return this.featureReferenceSelection.referenceIterator();
352
    }
353

    
354
    @Override
355
    public void selectAll() throws DataException {
356
        this.featureReferenceSelection.selectAll();
357
    }
358

    
359
    @Override
360
    public void deselectAll() throws DataException {
361
        this.featureReferenceSelection.deselectAll();
362
    }
363
    
364
    public void deselectAll(boolean undoable) throws DataException {
365
        this.featureReferenceSelection.deselectAll(undoable);
366
    }
367
    
368
    @Override
369
    public boolean isSelected(FeatureReference reference) {
370
        return this.featureReferenceSelection.isSelected(reference);
371
    }
372

    
373
    @Override
374
    public void reverse() {
375
        this.featureReferenceSelection.reverse();
376
    }
377

    
378
    @Override
379
    public void dispose() {
380
        this.featureReferenceSelection.dispose();
381
    }
382

    
383
    @Override
384
    public void update(Observable o, Object o1) {
385
        this.featureReferenceSelection.update(o, o1);
386
    }
387

    
388
    @Override
389
    public void addObserver(Observer obsrvr) {
390
        this.featureReferenceSelection.addObserver(obsrvr);
391
    }
392

    
393
    @Override
394
    public void deleteObserver(Observer obsrvr) {
395
        this.featureReferenceSelection.deleteObserver(obsrvr);
396
    }
397

    
398
    @Override
399
    public void deleteObservers() {
400
        this.featureReferenceSelection.deleteObservers();
401
    }
402

    
403
    @Override
404
    public void beginComplexNotification() {
405
        this.featureReferenceSelection.beginComplexNotification();
406
    }
407

    
408
    @Override
409
    public void endComplexNotification() {
410
        this.featureReferenceSelection.endComplexNotification();
411
    }
412

    
413
    @Override
414
    public void saveToState(PersistentState ps) throws PersistenceException {
415
        this.featureReferenceSelection.saveToState(ps);
416
    }
417

    
418
    @Override
419
    public boolean select(Feature feature) {
420
        return select(feature, true);
421
    }
422

    
423
    /**
424
     * @param feature
425
     * @return
426
     * @see #select(Feature)
427
     * @param undoable if the action must be undoable
428
     */
429
    public boolean select(Feature feature, boolean undoable) {
430
        // TODO: should we check if the feature is from the same FeatureStore??
431
        if (feature == null) {
432
            return false;
433
        }
434

    
435
        // LOGGER.debug("Selected feature: {}", feature);
436
        if (isReversed()) {
437
            removeFeatureTypeCount(feature.getType());
438
        } else {
439
            addFeatureTypeCount(feature.getType());
440
        }
441
        return select(feature.getReference(), undoable);
442
    }
443

    
444
    @Override
445
    public boolean select(FeatureSet features) throws DataException {
446
        return select(features, true);
447
    }
448

    
449
    /**
450
     * @param features
451
     * @return
452
     * @throws org.gvsig.fmap.dal.exception.DataException
453
     * @see #select(FeatureSet)
454
     * @param undoable if the action must be undoable
455
     */
456
    public boolean select(FeatureSet features, boolean undoable)
457
            throws DataException {
458
        boolean change = false;
459
        boolean inComplex = false;
460
        if (undoable && this.featureReferenceSelection.getFeatureStore().isEditing()
461
                && !this.featureReferenceSelection.getCommands().inComplex()) {
462

    
463
            this.featureReferenceSelection.getCommands().startComplex("_selectionSelectFeatureSet");
464
            inComplex = this.featureReferenceSelection.getCommands().inComplex();
465
        }
466

    
467
        disableNotifications();
468
        DisposableIterator iter = null;
469
        try {
470
            for (iter = features.fastIterator(); iter.hasNext();) {
471
                change |= select((Feature) iter.next(), undoable);
472
            }
473
        } finally {
474
            DisposeUtils.disposeQuietly(iter);
475
        }
476
        enableNotifications();
477
        if (undoable && getFeatureStore().isEditing() && inComplex) {
478
            getCommands().endComplex();
479
        }
480
        if (change) {
481
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
482
        }
483
        return change;
484
    }
485

    
486
    @Override
487
    public boolean deselect(Feature feature) {
488
        return deselect(feature, true);
489
    }
490

    
491
    /**
492
     * @param feature
493
     * @return
494
     * @see #deselect(Feature)
495
     * @param undoable if the action must be undoable
496
     */
497
    public boolean deselect(Feature feature, boolean undoable) {
498
        if (feature == null) {
499
            return false;
500
        }
501

    
502
        LOG.debug("Deselected feature: {}", feature);
503

    
504
        if (isReversed()) {
505
            addFeatureTypeCount(feature.getType());
506
        } else {
507
            removeFeatureTypeCount(feature.getType());
508
        }
509
        return deselect(feature.getReference(), undoable);
510
    }
511

    
512
    @Override
513
    public boolean deselect(FeatureSet features) throws DataException {
514
        return deselect(features, true);
515
    }
516

    
517
    /**
518
     * @param features
519
     * @return
520
     * @throws org.gvsig.fmap.dal.exception.DataException
521
     * @see #deselect(FeatureSet)
522
     * @param undoable if the action must be undoable
523
     */
524
    public boolean deselect(FeatureSet features, boolean undoable)
525
            throws DataException {
526
        boolean change = false;
527
        if (undoable && getFeatureStore().isEditing()) {
528
            getCommands().startComplex("_selectionDeselectFeatureSet");
529
        }
530
        disableNotifications();
531
        DisposableIterator iter = null;
532
        try {
533
            for (iter = features.fastIterator(); iter.hasNext();) {
534
                change |= deselect((Feature) iter.next(), undoable);
535
            }
536
        } finally {
537
            DisposeUtils.disposeQuietly(iter);
538
        }
539
        enableNotifications();
540
        if (undoable && getFeatureStore().isEditing()) {
541
            getCommands().endComplex();
542
        }
543
        if (change) {
544
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
545
        }
546
        return change;
547
    }
548

    
549
    @Override
550
    public boolean isSelected(Feature feature) {
551
        if (feature == null) {
552
            return false;
553
        }
554
        if( this.featureReferenceSelection.isEmpty() ) {
555
            return false;
556
        }
557
        // Use the selection data size as a small optimization for the most
558
        // common case, when nothing is selected and every feature is checked
559
        // while drawing or painting the table document.
560
        if (getData().isReversed()) {
561
            return getData().getSize() == 0
562
                    || !getData().contains(feature.getReference());
563
        } else {
564
            return getData().getSize() > 0
565
                    && getData().contains(feature.getReference());
566
        }
567
    }
568

    
569
    @Override
570
    public FeatureType getDefaultFeatureType() {
571
        try {
572
            return getFeatureStore().getDefaultFeatureType();
573
        } catch (DataException ex) {
574
            LOG.error("Error getting the default feature type "
575
                    + "of the FeatureStore: " + getFeatureStore(), ex);
576
        }
577
        return null;
578
    }
579

    
580
    @Override
581
    public List getFeatureTypes() {
582
        // Go through the map of FeatureTypes, and return only the ones that
583
        // have at least a Feature.
584
        List types = new ArrayList();
585
        for (java.util.Iterator iterator = featureTypeCounts.entrySet()
586
                .iterator(); iterator.hasNext();) {
587
            Map.Entry entry = (Entry) iterator.next();
588
            FeatureType type = (FeatureType) entry.getKey();
589
            Long count = (Long) entry.getValue();
590

    
591
            if (count > 0) {
592
                types.add(type);
593
            }
594
        }
595

    
596
        return types;
597
    }
598

    
599
    @Override
600
    public long getSize() throws DataException {
601
        return getSelectedCount();
602
    }
603

    
604
    /**
605
     * Returns the list of selected values, or the deselected ones if the
606
     * selection has been reversed.
607
     *
608
     * WARN: not very good performance implementation.
609
     */
610
    @Override
611
        public DisposableIterator iterator(long index) {
612
                return iterator(index, 0, false);
613
        }
614

    
615
    @Override
616
        public DisposableIterator iterator(long index, long elements) {
617
                return iterator(index, elements, false);
618
        }
619

    
620
    /**
621
     * Returns the list of selected values, or the deselected ones if the
622
     * selection has been reversed.
623
     *
624
     * WARN: not really a fast implementation.
625
     */
626
    @Override
627
        public DisposableIterator fastIterator(long index) {
628
            return fastIterator(index, 0);
629
        }
630

    
631
    @Override
632
    public DisposableIterator fastIterator(long index, long elements) {
633
        return iterator(index, elements, true);
634
    }
635

    
636

    
637
    protected void clearFeatureReferences() {
638
        this.featureReferenceSelection.clearFeatureReferences();
639
        featureTypeCounts.clear();
640
    }
641

    
642
    /**
643
     * Creates an iterator for the Selection.
644
     */
645
    private DisposableIterator iterator(long index, long elements, boolean fastIterator) {
646
        if (isReversed()) {
647
            DisposableIterator iter = new ReversedFeatureIteratorFacade(
648
                    getData(), getFeatureStore(), fastIterator);
649
            for (long l = 0; l < index && iter.hasNext(); l++) {
650
                iter.next();
651
            }
652
            return iter;
653

    
654
        } else {
655
            // TODO: maybe we could add a new referenceIterator(int index)
656
            // method that could be implemented in a more performant way
657

    
658
            java.util.Iterator iter = getData().getSelected().iterator();
659
            for (long l = 0; l < index && iter.hasNext(); l++) {
660
                iter.next();
661
            }
662
            return new FeatureIteratorFacade(iter, getFeatureStore());
663
        }
664
    }
665

    
666
    private Long removeFeatureTypeCount(FeatureType featureType) {
667
        Long count = (Long) featureTypeCounts.get(featureType);
668
        if (count == null) {
669
            count = new Long(-1);
670
        } else {
671
            count = count - 1;
672
        }
673
        featureTypeCounts.put(featureType, count);
674
        return count;
675
    }
676

    
677
    private Long addFeatureTypeCount(FeatureType featureType) {
678
        Long count = (Long) featureTypeCounts.get(featureType);
679
        if (count == null) {
680
            count = new Long(1);
681
        } else {
682
            count = count + 1;
683
        }
684
        featureTypeCounts.put(featureType, count);
685
        return count;
686
    }
687

    
688
    @Override
689
    public void delete(Feature feature) throws DataException {
690
        Iterator it = this.featureIterators.get(feature);
691
        if (it != null) {
692
            it.remove();
693
            return;
694
        }
695
        feature.getStore().delete(feature);
696
    }
697

    
698
    @Override
699
    public void insert(EditableFeature feature) throws DataException {
700
        feature.getStore().insert(feature);
701
    }
702

    
703
    @Override
704
    public void update(EditableFeature feature) throws DataException {
705
        feature.getStore().update(feature);
706
    }
707
    
708
    
709
    @Override
710
    public void commitChanges() throws DataException {
711
    }
712

    
713
    /*
714
     * (non-Javadoc)
715
     *
716
     * @seeorg.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection#
717
     * loadFromState(org.gvsig.tools.persistence.PersistentState)
718
     */
719
    @Override
720
    public void loadFromState(PersistentState state)
721
            throws PersistenceException {
722
        this.featureReferenceSelection.loadFromState(state);
723
    }
724

    
725
    protected void doDispose() throws BaseException {
726
        this.featureReferenceSelection.doDispose();
727
        featureTypeCounts.clear();
728
    }
729

    
730
    public static void registerPersistent() {
731
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
732
        DynStruct definition = manager.addDefinition(
733
                DefaultFeatureSelection.class, "DefaultFeatureSelection",
734
                "DefaultFeatureSelection Persistent definition", null, null);
735

    
736
        definition.extend(manager.getDefinition(DefaultFeatureReferenceSelection.DYNCLASS_PERSISTENT_NAME));
737
        definition.addDynFieldMap("featureTypeCounts")
738
                .setClassOfItems(Long.class).setMandatory(false);
739

    
740
    }
741

    
742
    @Override
743
    public Object clone() throws CloneNotSupportedException {
744
        DefaultFeatureSelection clone = (DefaultFeatureSelection) super.clone();
745
        clone.featureTypeCounts = new HashMap(featureTypeCounts);
746
        return clone;
747
    }
748

    
749
    @Override
750
    protected void doAccept(Visitor visitor, long firstValueIndex, long elements) throws BaseException {
751
        if( this.featureReferenceSelection.isEmpty() ) {
752
            return;
753
        }
754
        DisposableIterator iterator = fastIterator(firstValueIndex, elements);
755
        if (iterator != null) {
756
            try {
757
                while (iterator.hasNext()) {
758
                    Feature feature = (Feature) iterator.next();
759
                    visitor.visit(feature);
760
                }
761
            } finally {
762
                iterator.dispose();
763
            }
764
        }
765
    }
766

    
767
}