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 / featureset / DefaultFeatureSet.java @ 43088

History | View | Annotate | Download (19.1 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
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * 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
 *
16
 * 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
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.impl.featureset;
25

    
26
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectSetFeatureSetFacade;
27
import java.util.ArrayList;
28
import java.util.Collections;
29
import java.util.Iterator;
30
import java.util.List;
31
import java.util.NoSuchElementException;
32

    
33
import org.gvsig.fmap.dal.DataStore;
34
import org.gvsig.fmap.dal.exception.DataException;
35
import org.gvsig.fmap.dal.feature.EditableFeature;
36
import org.gvsig.fmap.dal.feature.Feature;
37
import org.gvsig.fmap.dal.feature.FeatureIndexes;
38
import org.gvsig.fmap.dal.feature.FeatureQuery;
39
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
40
import org.gvsig.fmap.dal.feature.FeatureQueryOrder.FeatureQueryOrderMember;
41
import org.gvsig.fmap.dal.feature.FeatureSet;
42
import org.gvsig.fmap.dal.feature.FeatureStore;
43
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
44
import org.gvsig.fmap.dal.feature.FeatureType;
45
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
46
import org.gvsig.fmap.dal.feature.exception.FeatureSetInitializeException;
47
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureStore;
48
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureStoreTransforms;
49
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
50
import org.gvsig.tools.dispose.DisposableIterator;
51
import org.gvsig.tools.dispose.DisposeUtils;
52
import org.gvsig.tools.dynobject.DynObjectSet;
53
import org.gvsig.tools.evaluator.Evaluator;
54
import org.gvsig.tools.exception.BaseException;
55
import org.gvsig.tools.observer.Observable;
56
import org.gvsig.tools.observer.Observer;
57
import org.gvsig.tools.visitor.VisitCanceledException;
58
import org.gvsig.tools.visitor.Visitor;
59
import org.gvsig.tools.visitor.impl.AbstractIndexedVisitable;
60

    
61
public class DefaultFeatureSet extends AbstractIndexedVisitable implements
62
    FeatureSet, Observer {
63

    
64
    private static final int NO_CHECKED = -1;
65
    private static final int DEFAULT = 0;
66
    private static final int FILTERED = 1;
67
    private static final int ORDERED = 2;
68
    private static final int ORDERED_FILTERED = 3;
69
    private static final int EDITED = 4;
70
    private static final int EDITED_FILTERED = 5;
71
    private static final int ORDERD_EDITED = 6;
72
    private static final int ORDERED_EDITED_FILTER = 7;
73

    
74
    private boolean sourceStoreModified;
75
    private boolean ownFeaturesModified;
76
    DefaultFeatureStore store;
77
    private List featureTypes;
78
    FeatureQuery query;
79
    FeatureSetProvider provider;
80
    private long size;
81
    private int iteratorMode;
82
    List orderedData;
83
    private Feature featureToIgnoreNotification;
84
    DefaultFeatureStoreTransforms transform;
85
    private FeatureQuery queryForProvider;
86
    private FeatureType defatulFeatureType;
87
    private FeatureType defatulFeatureTypeForProvider;
88

    
89
    public DefaultFeatureSet(DefaultFeatureStore store, FeatureQuery query)
90
        throws DataException {
91
        this.featureToIgnoreNotification = null;
92
        this.iteratorMode = NO_CHECKED;
93
        this.sourceStoreModified = false;
94
        this.ownFeaturesModified = false;
95
        this.size = -1;
96
        this.orderedData = null;
97
        this.store = store;
98
        if (this.store.isEditing()) {
99
            this.transform = this.store.getFeatureTypeManager().getTransforms();
100
        } else {
101
            this.transform =
102
                (DefaultFeatureStoreTransforms) store.getTransforms();
103
        }
104
        this.query = query;
105
        try {
106
            this.queryForProvider = (FeatureQuery) query.clone();
107
        } catch (CloneNotSupportedException e) {
108
            throw new FeatureSetInitializeException(e);
109
        }
110

    
111
        this.featureTypes = new ArrayList();
112
        if (this.query.getFeatureTypeId() == null
113
            && this.query.getAttributeNames() == null) {
114
            this.defatulFeatureType = this.store.getDefaultFeatureType();
115
            this.featureTypes.addAll(this.store.getFeatureTypes());
116
        } else {
117
            this.defatulFeatureType = this.store.getFeatureType(this.query);
118
            this.featureTypes.add(this.defatulFeatureType);
119
        }
120
        if (this.transform != null && !this.transform.isEmpty()) {
121
            this.fixQueryForProvider(this.queryForProvider, this.transform);
122
        } else {
123
            this.defatulFeatureTypeForProvider = this.defatulFeatureType;
124
        }
125

    
126
        FeatureIndexes indexes = store.getIndexes();
127
        if (this.queryForProvider.hasFilter() && indexes != null
128
            && indexes.areValid()) {
129
            this.provider =
130
                (FeatureSetProvider) indexes
131
                    .getFeatureSet(this.queryForProvider.getFilter());
132
        }
133
        if (this.provider == null) {
134
            this.provider =
135
                this.store.getProvider().createSet(this.queryForProvider,
136
                    this.defatulFeatureTypeForProvider);
137
        }
138
        this.store.addObserver(this);
139
    }
140

    
141
    private void fixQueryForProvider(FeatureQuery theQueryForProvider,
142
        DefaultFeatureStoreTransforms transformsToUse) throws DataException {
143
        theQueryForProvider.clearAttributeNames();
144
        FeatureType ftype =
145
            transformsToUse.getSourceFeatureTypeFrom(this.defatulFeatureType);
146
        theQueryForProvider.setFeatureTypeId(ftype.getId());
147
        this.defatulFeatureTypeForProvider = ftype;
148

    
149
        if (transformsToUse.isTransformsOriginalValues()) {
150
            theQueryForProvider.clearFilter();
151
            FeatureQueryOrder fqo = theQueryForProvider.getOrder();
152
            if (fqo != null) {
153
                fqo.clear();
154
            }
155
            return;
156

    
157
        }
158

    
159
        // Filter
160
        Evaluator filter = theQueryForProvider.getFilter();
161
        if (filter != null) {
162
            boolean canUseFilter = true;
163
            if (filter.getFieldsInfo() == null) {
164
                canUseFilter = false;
165
            } else {
166
                canUseFilter = areEvaluatorFieldsInAttributes(filter, ftype);
167
            }
168

    
169
            if (!canUseFilter) {
170
                theQueryForProvider.clearFilter();
171
            }
172

    
173
        }
174

    
175
        // Order
176
        if (theQueryForProvider.hasOrder()) {
177
            boolean canUseOrder = true;
178
            Iterator iter = theQueryForProvider.getOrder().iterator();
179
            FeatureQueryOrderMember item;
180
            while (iter.hasNext()) {
181
                item = (FeatureQueryOrderMember) iter.next();
182
                if (item.hasEvaluator()) {
183
                    if (!areEvaluatorFieldsInAttributes(item.getEvaluator(),
184
                        ftype)) {
185
                        canUseOrder = false;
186
                        break;
187
                    }
188
                } else {
189
                    if (ftype.get(item.getAttributeName()) == null) {
190
                        canUseOrder = false;
191
                        break;
192
                    }
193
                }
194
            }
195

    
196
            if (!canUseOrder) {
197
                theQueryForProvider.getOrder().clear();
198
            }
199
        }
200

    
201
    }
202

    
203
    private boolean areEvaluatorFieldsInAttributes(Evaluator evaluator,
204
        FeatureType fType) {
205
        if (evaluator.getFieldsInfo() == null) {
206
            return false;
207
        }
208
        String[] fieldNames = evaluator.getFieldsInfo().getFieldNames();
209
        if (fieldNames.length == 0) {
210
            return false;
211
        } else {
212
            for (int i = 0; i < fieldNames.length; i++) {
213
                if (fType.get(fieldNames[i]) == null) {
214
                    return false;
215
                }
216

    
217
            }
218
        }
219
        return true;
220
    }
221

    
222
    public FeatureType getDefaultFeatureType() {
223
        return this.defatulFeatureType;
224
    }
225

    
226
    public List getFeatureTypes() {
227
        return Collections.unmodifiableList(this.featureTypes);
228
    }
229

    
230
    public long getSize() throws DataException {
231
        this.checkSourceStoreModified();
232
        if (size < 0) {
233
            size = calculateSize();
234
        }
235
        return size;
236
    }
237

    
238
    private long calculateSize() throws DataException {
239
        int mode = this.getIteratorMode();
240
        if ((mode & EDITED) != EDITED) {
241
            if (this.provider.isEmpty()) {
242
                return 0;
243
            }
244
        }
245
        if ((mode & FILTERED) == FILTERED) {
246
            long mySize = 0;
247
            DisposableIterator iter = null;
248
            try {
249
                iter = this.fastIterator();
250
                while (true) {
251
                    iter.next();
252
                    mySize++;
253
                }
254
            } catch (NoSuchElementException e) {
255
                return mySize;
256
            } finally {
257
                iter.dispose();
258
            }
259
        } else
260
            if ((mode & EDITED) == EDITED) {
261
                return provider.getSize()
262
                    + store.getFeatureManager().getDeltaSize();
263
            }
264
        return provider.getSize();
265
    }
266

    
267
    public void dispose() {
268
        this.store.deleteObserver(this);
269
        this.provider.dispose();
270
        this.provider = null;
271

    
272
        this.featureToIgnoreNotification = null;
273
        if (orderedData != null) {
274
            orderedData.clear();
275
        }
276
        this.orderedData = null;
277
        this.store = null;
278
        this.transform = null;
279
        this.query = null;
280
        this.queryForProvider = null;
281
        this.featureTypes = null;
282
        this.defatulFeatureType = null;
283
        this.defatulFeatureTypeForProvider = null;
284
    }
285

    
286
    public boolean isFromStore(DataStore store) {
287
        return this.store.equals(store);
288
    }
289

    
290
    public void update(Observable obsevable, Object notification) {
291
        if (sourceStoreModified) {
292
            return;
293
        }
294

    
295
        String type = ((FeatureStoreNotification) notification).getType();
296

    
297
        if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_INSERT)
298
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_DELETE)
299
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UPDATE)) {
300
            if (this.featureToIgnoreNotification == ((FeatureStoreNotification) notification)
301
                .getFeature()) {
302
                return;
303
            }
304
            sourceStoreModified = true;
305
            return;
306
        }
307
        if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UPDATE_TYPE)
308
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_REDO)
309
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UNDO)
310
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_REFRESH)
311
            || type
312
                .equalsIgnoreCase(FeatureStoreNotification.COMPLEX_NOTIFICATION)
313
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_CLOSE)
314
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_DISPOSE)
315
            || type.equalsIgnoreCase(FeatureStoreNotification.RESOURCE_CHANGED)
316
            || type.equalsIgnoreCase(FeatureStoreNotification.TRANSFORM_CHANGE)) {
317
            sourceStoreModified = true;
318
            return;
319
        }
320
        if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_CANCELEDITING)
321
            && ownFeaturesModified) {
322
            sourceStoreModified = true;
323
            return;
324
        }
325
    }
326

    
327
    protected void doAccept(Visitor visitor, long firstValueIndex)
328
        throws VisitCanceledException, BaseException {
329
        DisposableIterator iterator = fastIterator(firstValueIndex);
330

    
331
        try {
332
            while (iterator.hasNext()) {
333
                Feature feature = (Feature) iterator.next();
334
                visitor.visit(feature);
335
            }
336
        } finally {
337
            iterator.dispose();
338
        }
339
    }
340

    
341
    protected void checkSourceStoreModified() {
342
        if (sourceStoreModified) {
343
                        throw new ConcurrentDataModificationException(store == null ? ""
344
                                        : store.getName());
345
        }
346
    }
347

    
348
    public boolean isEmpty() throws DataException {
349
        checkSourceStoreModified();
350
        return this.getSize() == 0;
351
    }
352

    
353
    @Override
354
    public Feature first() {
355
        DisposableIterator it = null;
356
        try {
357
            it = this.iterator();
358
            if( it == null ) {
359
                return null;
360
            }
361
            Feature f = (Feature) it.next();
362
            return f;
363
        } finally {
364
            DisposeUtils.disposeQuietly(it);
365
        }
366
    }
367

    
368

    
369
    public DisposableIterator fastIterator() throws DataException {
370
        return this.fastIterator(0);
371
    }
372

    
373
    public DisposableIterator fastIterator(long index) throws DataException {
374
        if (index < 0) {
375
            throw new IndexOutOfBoundsException("The index (" + index
376
                + ") is less than 0");
377
        }
378
        int mode = this.getIteratorMode();
379

    
380
        switch (mode) {
381
        case DEFAULT:
382
            return new FastDefaultIterator(this, index);
383

    
384
        case FILTERED:
385
            return new FastFilteredIterator(this, index);
386

    
387
        case ORDERED:
388
            if (this.orderedData != null) {
389
                return new FastOrderedIterator(this, index);
390
            } else {
391
                return new FastOrderedIterator(this, new FastDefaultIterator(
392
                    this, 0), index);
393
            }
394

    
395
        case ORDERED_FILTERED:
396
            if (this.orderedData != null) {
397
                return new FastOrderedIterator(this, index);
398
            } else {
399
                return new FastOrderedIterator(this, new FastFilteredIterator(
400
                    this, 0), index);
401
            }
402

    
403
        case EDITED:
404
            return new FastEditedIterator(this, index);
405

    
406
        case EDITED_FILTERED:
407
            return new FastEditedFilteredIterator(this, index);
408

    
409
        case ORDERD_EDITED:
410
            if (this.orderedData != null) {
411
                return new FastOrderedIterator(this, index);
412
            } else {
413
                return new FastOrderedIterator(this, new FastEditedIterator(
414
                    this, 0), index);
415
            }
416

    
417
        case ORDERED_EDITED_FILTER:
418
            if (this.orderedData != null) {
419
                return new FastOrderedIterator(this, index);
420
            } else {
421
                return new FastOrderedIterator(this,
422
                    new FastEditedFilteredIterator(this, 0), index);
423
            }
424
        default:
425
            throw new IllegalArgumentException();
426
        }
427
    }
428

    
429
    public DisposableIterator iterator() {
430
        try {
431
            return this.fastIterator(0);
432
        } catch (DataException ex) {
433
            throw new RuntimeException("Can't obtain itertor.",ex);
434
        }
435
    }
436

    
437
    public DisposableIterator iterator(long index) throws DataException {
438
        if (index < 0) {
439
            throw new IndexOutOfBoundsException("The index (" + index
440
                + ") is less than 0");
441
        }
442
        int mode = this.getIteratorMode();
443

    
444
        switch (mode) {
445
        case DEFAULT:
446
            return new DefaultIterator(this, index);
447

    
448
        case FILTERED:
449
            return new FilteredIterator(this, index);
450

    
451
        case ORDERED:
452
            if (orderedData != null) {
453
                return new OrderedIterator(this, index);
454

    
455
            } else {
456
                return new OrderedIterator(this, new DefaultIterator(this, 0),
457
                    index);
458
            }
459

    
460
        case ORDERED_FILTERED:
461
            return new OrderedIterator(this, new FilteredIterator(this, 0),
462
                index);
463

    
464
        case EDITED:
465
            return new EditedIterator(this, index);
466

    
467
        case EDITED_FILTERED:
468
            return new EditedFilteredIterator(this, index);
469

    
470
        case ORDERD_EDITED:
471
            return new OrderedIterator(this, new EditedIterator(this, 0), index);
472

    
473
        case ORDERED_EDITED_FILTER:
474
            return new OrderedIterator(this,
475
                new EditedFilteredIterator(this, 0), index);
476

    
477
        default:
478
            throw new IllegalArgumentException();
479
        }
480

    
481
    }
482

    
483
    private boolean providerCanOrder() {
484
        return this.provider.canOrder();
485
    }
486

    
487
    private boolean providerCanFilter() {
488
        return this.provider.canFilter();
489
    }
490

    
491
    private int getIteratorMode() {
492

    
493
        if (this.iteratorMode != NO_CHECKED) {
494
            return this.iteratorMode;
495
        }
496

    
497
        // TODO Tener en cuenta las transformaciones ???
498

    
499
        if (store.isEditing() && store.getFeatureManager().hasChanges()) {
500
            if (this.query.hasOrder()) { // En edicion siempre ordeno yo.
501
                if (this.query.hasFilter()) {
502
                    return ORDERED_EDITED_FILTER;
503
                } else {
504
                    return ORDERD_EDITED;
505
                }
506
            } else {
507
                if (this.query.hasFilter()) {
508
                    return EDITED_FILTERED;
509
                } else {
510
                    return EDITED;
511
                }
512
            }
513
        } else {
514
            boolean useMyFilter = this.query.hasFilter();
515
            boolean useMyOrder = this.query.hasOrder();
516
            if (this.providerCanOrder() && this.transform.isEmpty()) {
517
                useMyOrder = false;
518
            }
519
            if (this.providerCanFilter() && this.transform.isEmpty()) {
520
                useMyFilter = false;
521
            }
522

    
523
            if (useMyOrder) {
524
                if (useMyFilter) {
525
                    return ORDERED_FILTERED;// ORDERED_FILTERED;
526
                } else {
527
                    return ORDERED;// ORDERED;
528
                }
529
            } else {
530
                if (useMyFilter) {
531
                    return FILTERED;// FILTERED;
532
                } else {
533
                    return DEFAULT;// DEFAULT;
534
                }
535
            }
536
        }
537

    
538
    }
539

    
540
    public void delete(Feature feature) throws DataException {
541
        this.featureToIgnoreNotification = feature;
542
        this.store.delete(feature);
543
        if (this.size > 0) {
544
            this.size--;
545
        }
546
        this.featureToIgnoreNotification = null;
547
        this.ownFeaturesModified = true;
548
    }
549

    
550
    public void insert(EditableFeature feature) throws DataException {
551
        this.featureToIgnoreNotification = feature;
552
        this.store.insert(feature);
553
        if (this.size >= 0) {
554
            this.size++;
555
        }
556
        this.featureToIgnoreNotification = null;
557
        this.ownFeaturesModified = true;
558
    }
559

    
560
    public void update(EditableFeature feature) throws DataException {
561
        this.featureToIgnoreNotification = feature;
562
        this.store.update(feature);
563
        this.featureToIgnoreNotification = null;
564
        this.ownFeaturesModified = true;
565
    }
566

    
567
    public DynObjectSet getDynObjectSet() {
568
        return this.getDynObjectSet(true);
569
    }
570

    
571
    public DynObjectSet getDynObjectSet(boolean fast) {
572
        return new DynObjectSetFeatureSetFacade(this, store, fast);
573
    }
574

    
575
    public FeatureStore getFeatureStore() {
576
        return store;
577
    }
578
}