Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_dal / src / org / gvsig / fmap / dal / feature / impl / DefaultFeatureSelection.java @ 31272

History | View | Annotate | Download (14.6 KB)

1 23824 cordinyana
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Gobernment (CIT)
5 23894 jjdelcerro
 *
6 23824 cordinyana
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10 23894 jjdelcerro
 *
11 23824 cordinyana
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15 23894 jjdelcerro
 *
16 23824 cordinyana
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18 23894 jjdelcerro
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 23824 cordinyana
 * MA  02110-1301, USA.
20 23894 jjdelcerro
 *
21 23824 cordinyana
 */
22
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2008 {DiSiD Technologies}  {Implement data selection}
26
 */
27 24496 jmvivo
package org.gvsig.fmap.dal.feature.impl;
28 23754 jjdelcerro
29 30208 jmvivo
import java.util.ArrayList;
30
import java.util.HashMap;
31
import java.util.List;
32
import java.util.Map;
33 24526 cordinyana
import java.util.Map.Entry;
34 23824 cordinyana
35 24496 jmvivo
import org.gvsig.fmap.dal.DataStoreNotification;
36 24505 jmvivo
import org.gvsig.fmap.dal.exception.DataException;
37 30208 jmvivo
import org.gvsig.fmap.dal.feature.DisposableIterator;
38
import org.gvsig.fmap.dal.feature.EditableFeature;
39
import org.gvsig.fmap.dal.feature.Feature;
40
import org.gvsig.fmap.dal.feature.FeatureReference;
41
import org.gvsig.fmap.dal.feature.FeatureSelection;
42
import org.gvsig.fmap.dal.feature.FeatureSet;
43
import org.gvsig.fmap.dal.feature.FeatureStore;
44
import org.gvsig.fmap.dal.feature.FeatureType;
45 26833 cordinyana
import org.gvsig.fmap.dal.feature.exception.ReversedSelectionIteratorException;
46 30208 jmvivo
import org.gvsig.tools.ToolsLocator;
47
import org.gvsig.tools.dynobject.DynClass;
48
import org.gvsig.tools.dynobject.DynObjectManager;
49 31110 cordinyana
import org.gvsig.tools.exception.BaseException;
50 24527 cordinyana
import org.gvsig.tools.persistence.PersistenceException;
51
import org.gvsig.tools.persistence.PersistentState;
52 31110 cordinyana
import org.gvsig.tools.visitor.Visitor;
53 24023 cordinyana
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
55 23754 jjdelcerro
56 23824 cordinyana
/**
57 23928 cordinyana
 * Default implementation of the FeatureSelection interface. Internally, only
58
 * FeatureReference values are stored.
59 27264 vcaballero
 *
60 23928 cordinyana
 * This implementation performs better if used with the selection related
61
 * methods: select, deselect and isSelected ones.
62 27264 vcaballero
 *
63 23824 cordinyana
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
64
 */
65 23928 cordinyana
public class DefaultFeatureSelection extends DefaultFeatureReferenceSelection
66 31272 jpiera
implements FeatureSelection {
67 23754 jjdelcerro
68 31272 jpiera
        private static final Logger LOGGER = LoggerFactory
69
        .getLogger(DefaultFeatureSelection.class);
70 23754 jjdelcerro
71 31272 jpiera
        private Map featureTypeCounts = new HashMap(1);
72 24526 cordinyana
73 31272 jpiera
        /**
74
         * Creates a DefaultFeatureSelection, with a FeatureStore.
75
         *
76
         * @param featureStore
77
         *            the FeatureStore to load Features from
78
         * @throws DataException
79
         *             if there is an error while getting the total number of
80
         *             Features of the Store.
81
         * @see AbstractSetBasedDataSelection#DefaultSelection(int)
82
         */
83
        public DefaultFeatureSelection(DefaultFeatureStore featureStore)
84
        throws DataException {
85
                super(featureStore);
86
        }
87 23754 jjdelcerro
88 31272 jpiera
        /**
89
         * Creates a new Selection with the total size of Features from which the
90
         * selection will be performed.
91
         *
92
         * @param featureStore
93
         *            the FeatureStore of the selected FeatureReferences
94
         * @param helper
95
         *            to get some information of the Store
96
         * @throws DataException
97
         *             if there is an error while getting the total number of
98
         *             Features of the Store.
99
         */
100
        public DefaultFeatureSelection(FeatureStore featureStore,
101
                        FeatureSelectionHelper helper) throws DataException {
102
                super(featureStore, helper);
103
        }
104
105
         /**
106
     * Constructor used by the persistence manager. Don't use directly.
107
     * After to invoke this method, the persistence manager calls
108
     * the the method {@link #loadFromState(PersistentState)} to set
109
     * the values of the internal attributes that this class needs to work.
110 27719 cordinyana
     */
111 31272 jpiera
        public DefaultFeatureSelection() {
112
                super();
113
        }
114 27719 cordinyana
115 31272 jpiera
        public boolean select(Feature feature) {
116
                return select(feature, true);
117
        }
118 26318 cordinyana
119 31272 jpiera
        /**
120
         * @see #select(Feature)
121
         * @param undoable
122
         *            if the action must be undoable
123
         */
124
        public boolean select(Feature feature, boolean undoable) {
125
                // TODO: should we check if the feature is from the same FeatureStore??
126
                if (feature == null) {
127
                        return false;
128
                }
129 26833 cordinyana
130 31272 jpiera
                //        LOGGER.debug("Selected feature: {}", feature);
131 26833 cordinyana
132 31272 jpiera
                if (isReversed()) {
133
                        removeFeatureTypeCount(feature.getType());
134
                } else {
135
                        addFeatureTypeCount(feature.getType());
136
                }
137
                return select(feature.getReference(), undoable);
138
        }
139 23754 jjdelcerro
140 31272 jpiera
        public boolean select(FeatureSet features) throws DataException {
141
                return select(features, true);
142
        }
143 26317 cordinyana
144 31272 jpiera
        /**
145
         * @see #select(FeatureSet)
146
         * @param undoable
147
         *            if the action must be undoable
148
         */
149
        public boolean select(FeatureSet features, boolean undoable)
150
        throws DataException {
151
                boolean change = false;
152
                boolean inComplex = false;
153
                if (undoable && getFeatureStore().isEditing()
154 27297 jmvivo
                                && !getCommands().inComplex()) {
155
                        inComplex = getCommands().inComplex();
156
                        getCommands().startComplex("_selectionSelectFeatureSet");
157 31272 jpiera
                }
158 24194 jjdelcerro
159 31272 jpiera
                disableNotifications();
160
                for (DisposableIterator iter = features.fastIterator(); iter.hasNext();) {
161
                        change |= select((Feature) iter.next(), undoable);
162
                }
163
                enableNotifications();
164
                if (undoable && getFeatureStore().isEditing() && !inComplex) {
165
                        getCommands().endComplex();
166
                }
167
                if (change) {
168
                        notifyObservers(DataStoreNotification.SELECTION_CHANGE);
169
                }
170
                return change;
171
        }
172 23928 cordinyana
173 31272 jpiera
        public boolean deselect(Feature feature) {
174
                return deselect(feature, true);
175
        }
176 26318 cordinyana
177 31272 jpiera
        /**
178
         * @see #deselect(Feature)
179
         * @param undoable
180
         *            if the action must be undoable
181
         */
182
        public boolean deselect(Feature feature, boolean undoable) {
183
                if (feature == null) {
184
                        return false;
185
                }
186 26833 cordinyana
187 31272 jpiera
                LOGGER.debug("Deselected feature: {}", feature);
188 25801 cordinyana
189 31272 jpiera
                if (isReversed()) {
190
                        addFeatureTypeCount(feature.getType());
191
                } else {
192
                        removeFeatureTypeCount(feature.getType());
193
                }
194
                return deselect(feature.getReference(), undoable);
195
        }
196 23928 cordinyana
197 31272 jpiera
        public boolean deselect(FeatureSet features) throws DataException {
198
                return deselect(features, true);
199
        }
200 26317 cordinyana
201 31272 jpiera
        /**
202
         * @see #deselect(FeatureSet)
203
         * @param undoable
204
         *            if the action must be undoable
205
         */
206
        public boolean deselect(FeatureSet features, boolean undoable)
207
        throws DataException {
208
                boolean change = false;
209
                if (undoable && getFeatureStore().isEditing()) {
210
                        getCommands().startComplex("_selectionDeselectFeatureSet");
211
                }
212
                disableNotifications();
213
                for (DisposableIterator iter = features.fastIterator(); iter.hasNext();) {
214
                        change |= deselect((Feature) iter.next(), undoable);
215
                }
216
                enableNotifications();
217
                if (undoable && getFeatureStore().isEditing()) {
218
                        getCommands().endComplex();
219
                }
220
                if (change) {
221
                        notifyObservers(DataStoreNotification.SELECTION_CHANGE);
222
                }
223
                return change;
224
        }
225 23928 cordinyana
226 31272 jpiera
        public boolean isSelected(Feature feature) {
227
                if (feature == null) {
228
                        return false;
229
                }
230
                return isSelected(feature.getReference());
231
        }
232 23928 cordinyana
233 31272 jpiera
        public FeatureType getDefaultFeatureType() {
234
                try {
235
                        return getFeatureStore().getDefaultFeatureType();
236
                } catch (DataException ex) {
237
                        LOGGER.error("Error getting the default feature type "
238
                                        + "of the FeatureStore: " + getFeatureStore(), ex);
239
                }
240
                return null;
241
        }
242 23754 jjdelcerro
243 31272 jpiera
        public List getFeatureTypes() {
244
                // Go through the map of FeatureTypes, and return only the ones that
245
                // have at least a Feature.
246
                List types = new ArrayList();
247
                for (java.util.Iterator iterator = featureTypeCounts.entrySet()
248 27525 jmvivo
                                .iterator(); iterator
249 31272 jpiera
                                .hasNext();) {
250
                        Map.Entry entry = (Entry) iterator.next();
251
                        FeatureType type = (FeatureType) entry.getKey();
252
                        Long count = (Long) entry.getValue();
253 24526 cordinyana
254 31272 jpiera
                        if (count.longValue() > 0) {
255
                                types.add(type);
256
                        }
257
                }
258 24526 cordinyana
259 31272 jpiera
                return types;
260
        }
261 23754 jjdelcerro
262 31272 jpiera
        public long getSize() throws DataException {
263
                return getSelectedCount();
264
        }
265 23824 cordinyana
266 31272 jpiera
        public boolean isEmpty() throws DataException {
267
                return getSelectedCount() == 0;
268
        }
269 23928 cordinyana
270 31272 jpiera
        /**
271
         * Returns the list of selected values, or the deselected ones if the
272
         * selection has been reversed.
273
         */
274
        public DisposableIterator iterator() {
275
                return iterator(0);
276
        }
277 23928 cordinyana
278 31272 jpiera
        /**
279
         * Returns the list of selected values, or the deselected ones if the
280
         * selection has been reversed.
281
         *
282
         * WARN: not very good performance implementation.
283
         */
284
        public DisposableIterator iterator(long index) {
285
                return iterator(index, false);
286
        }
287 23824 cordinyana
288 31272 jpiera
        /**
289
         * Returns the list of selected values, or the deselected ones if the
290
         * selection has been reversed.
291
         *
292
         * WARN: not really a fast implementation.
293
         */
294
        public DisposableIterator fastIterator() {
295
                return fastIterator(0);
296
        }
297 23824 cordinyana
298 31272 jpiera
        /**
299
         * Returns the list of selected values, or the deselected ones if the
300
         * selection has been reversed.
301
         *
302
         * WARN: not really a fast implementation.
303
         */
304
        public DisposableIterator fastIterator(long index) {
305
                return iterator(index, true);
306
        }
307 24684 jjdelcerro
308 26833 cordinyana
309 31272 jpiera
        protected void clearFeatureReferences() {
310
                super.clearFeatureReferences();
311
                featureTypeCounts.clear();
312
        }
313 24526 cordinyana
314 31272 jpiera
        /**
315
         * Creates an iterator for the Selection.
316
         */
317
        private DisposableIterator iterator(long index, boolean fastIterator) {
318
                if (isReversed()) {
319
                        DisposableIterator iter = new ReversedFeatureIteratorFacade(getData(),
320
                                        getFeatureStore(), fastIterator);
321
                        for (long l = 0; l < index && iter.hasNext(); l++) {
322
                                iter.next();
323
                        }
324
                        return iter;
325 26833 cordinyana
326 31272 jpiera
                } else {
327
                        // TODO: maybe we could add a new referenceIterator(int index)
328
                // method that could be implemented in a more performant way
329 26833 cordinyana
330 31272 jpiera
                        java.util.Iterator iter = referenceIterator();
331
                        for (long l = 0; l < index && iter.hasNext(); l++) {
332
                                iter.next();
333
                        }
334
                        return new FeatureIteratorFacade(iter, getFeatureStore());
335
                }
336
        }
337 26833 cordinyana
338 31272 jpiera
        private Long removeFeatureTypeCount(FeatureType featureType) {
339 30208 jmvivo
                Long count = (Long) featureTypeCounts.get(featureType);
340
                if (count == null) {
341
                        count = new Long(-1);
342
                } else {
343
                        count = new Long(count.longValue() - 1);
344
                }
345
                featureTypeCounts.put(featureType, count);
346
                return count;
347
        }
348
349
        private Long addFeatureTypeCount(FeatureType featureType) {
350
                Long count = (Long) featureTypeCounts.get(featureType);
351
                if (count == null) {
352
                        count = new Long(1);
353
                } else {
354
                        count = new Long(count.longValue() + 1);
355
                }
356
                featureTypeCounts.put(featureType, count);
357
                return count;
358 31272 jpiera
        }
359 24526 cordinyana
360 31272 jpiera
        /**
361
         * Facade over a Iterator of FeatureReferences, to return Features instead.
362
         *
363
         * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
364
         */
365
        private class FeatureIteratorFacade implements DisposableIterator {
366 24151 cordinyana
367 31272 jpiera
                final Logger logger = LoggerFactory
368
                .getLogger(FeatureIteratorFacade.class);
369 24151 cordinyana
370 31272 jpiera
                private java.util.Iterator refIterator;
371 24151 cordinyana
372 31272 jpiera
                private FeatureStore featureStore;
373 24269 cordinyana
374 31272 jpiera
                public FeatureIteratorFacade(java.util.Iterator iter,
375
                                FeatureStore featureStore) {
376
                        this.refIterator = iter;
377
                        this.featureStore = featureStore;
378
                }
379 24151 cordinyana
380 31272 jpiera
                public boolean hasNext() {
381
                        return refIterator.hasNext();
382
                }
383 24151 cordinyana
384 31272 jpiera
                public Object next() {
385
                        FeatureReference ref = nextFeatureReference();
386
                        try {
387
                                return featureStore.getFeatureByReference(ref);
388
                        } catch (DataException ex) {
389
                                logger.error(
390
                                                "Error loading the Feature with FeatureReference: "
391
                                                + ref, ex);
392
                                return null;
393
                        }
394
                }
395 24151 cordinyana
396 31272 jpiera
                /**
397
                 * Returns the next FeatureReference.
398
                 *
399
                 * @return the next FeatureReference
400
                 */
401
                public FeatureReference nextFeatureReference() {
402
                        return (FeatureReference) refIterator.next();
403
                }
404 24151 cordinyana
405 31272 jpiera
                public void remove() {
406
                        refIterator.remove();
407
                }
408 24151 cordinyana
409 31272 jpiera
                public void dispose() {
410 27672 jmvivo
                        if (refIterator instanceof DisposableIterator) {
411
                                ((DisposableIterator) refIterator).dispose();
412
                        }
413 27525 jmvivo
                        refIterator = null;
414
                        featureStore = null;
415
                }
416 31272 jpiera
        }
417 24526 cordinyana
418 31272 jpiera
        /**
419
         * Facade over a Iterator of FeatureReferences, to return Features instead,
420
         * when the Selection is reversed
421
         *
422
         * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
423
         */
424
        private class ReversedFeatureIteratorFacade implements DisposableIterator {
425 26833 cordinyana
426 31272 jpiera
                private SelectionData selectionData;
427 26833 cordinyana
428 31272 jpiera
                private DisposableIterator iterator;
429 26833 cordinyana
430 31272 jpiera
                private Feature nextFeature = null;
431 26833 cordinyana
432 27672 jmvivo
                private FeatureSet featureSet;
433
434 31272 jpiera
                public ReversedFeatureIteratorFacade(SelectionData selectionData,
435
                                FeatureStore featureStore, boolean fastIterator) {
436
                        this.selectionData = selectionData;
437 26833 cordinyana
438 31272 jpiera
                        // Load a Set with all the store features
439
                        try {
440
                                featureSet = featureStore.getFeatureSet();
441
                                if (fastIterator) {
442
                                        iterator = featureSet.fastIterator();
443
                                } else {
444
                                        iterator = featureSet.iterator();
445
                                }
446
                        } catch (DataException ex) {
447
                                throw new ReversedSelectionIteratorException(ex);
448
                        }
449 26833 cordinyana
450 31272 jpiera
                        // Filter the features not selected and position in the next
451
                        // selected feature
452
                        positionInNextElement();
453
                }
454 26833 cordinyana
455 31272 jpiera
                public boolean hasNext() {
456
                        return nextFeature != null;
457
                }
458 26833 cordinyana
459 31272 jpiera
                public Object next() {
460
                        Feature tmp = nextFeature;
461
                        positionInNextElement();
462
                        return tmp;
463
                }
464 26833 cordinyana
465 31272 jpiera
                public void remove() {
466
                        iterator.remove();
467
                }
468 26833 cordinyana
469 31272 jpiera
                private void positionInNextElement() {
470
                        nextFeature = null;
471
                        while (iterator.hasNext()) {
472
                                nextFeature = (Feature) iterator.next();
473
                                if (selectionData.contains(nextFeature.getReference())) {
474
                                        nextFeature = null;
475
                                } else {
476
                                        break;
477
                                }
478
                        }
479
                }
480 27525 jmvivo
481
                public void dispose() {
482 27672 jmvivo
                        this.featureSet.dispose();
483 27525 jmvivo
                        this.iterator.dispose();
484
                        this.selectionData = null;
485
                        this.nextFeature = null;
486
                }
487 31272 jpiera
        }
488 26833 cordinyana
489 31272 jpiera
        public void delete(Feature feature) throws DataException {
490
                throw new UnsupportedOperationException();
491
        }
492 24684 jjdelcerro
493 31272 jpiera
        public void insert(EditableFeature feature) throws DataException {
494
                throw new UnsupportedOperationException();
495
        }
496 24684 jjdelcerro
497 31272 jpiera
        public void update(EditableFeature feature) throws DataException {
498
                throw new UnsupportedOperationException();
499
        }
500 30208 jmvivo
501
        /*
502
         * (non-Javadoc)
503
         *
504
         * @seeorg.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection#
505
         * loadFromState(org.gvsig.tools.persistence.PersistentState)
506
         */
507
        public void loadFromState(PersistentState state)
508 31272 jpiera
        throws PersistenceException {
509 30208 jmvivo
                super.loadFromState(state);
510
511
512
        }
513
514 31110 cordinyana
        public void accept(Visitor visitor) throws BaseException {
515
                accept(visitor, 0);
516
        }
517
518
        public void accept(Visitor visitor, long firstValueIndex)
519 31272 jpiera
        throws BaseException {
520 31110 cordinyana
                DisposableIterator iterator = fastIterator(firstValueIndex);
521
522
                if (iterator != null) {
523
                        try {
524
                                while (iterator.hasNext()) {
525
                                        Feature feature = (Feature) iterator.next();
526
                                        visitor.visit(feature);
527
                                }
528
                        } finally {
529
                                iterator.dispose();
530
                        }
531
                }
532
        }
533
534 30208 jmvivo
        public static void registerPersistent() {
535
                DynObjectManager dynMan = ToolsLocator.getDynObjectManager();
536 30568 cordinyana
                DynClass dynClass = dynMan.add(
537 30208 jmvivo
                                "DefaultFeatureSelection_Persistent",
538 31272 jpiera
                "DefaultFeatureSelection Persistent definition");
539 30208 jmvivo
540
                dynClass
541 31272 jpiera
                .extend(DefaultFeatureReferenceSelection.DYNCLASS_PERSISTENT_NAME);
542 31229 cordinyana
                dynClass.addDynFieldMap("featureTypeCounts").setMandatory(true);
543 30208 jmvivo
                ToolsLocator.getPersistenceManager().registerClass(
544 30563 cordinyana
                                DefaultFeatureSelection.class, dynClass);
545 30208 jmvivo
546
        }
547 23824 cordinyana
}