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 @ 42821

History | View | Annotate | Download (18.8 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.dynobject.DynObjectSet;
52
import org.gvsig.tools.evaluator.Evaluator;
53
import org.gvsig.tools.exception.BaseException;
54
import org.gvsig.tools.observer.Observable;
55
import org.gvsig.tools.observer.Observer;
56
import org.gvsig.tools.visitor.VisitCanceledException;
57
import org.gvsig.tools.visitor.Visitor;
58
import org.gvsig.tools.visitor.impl.AbstractIndexedVisitable;
59

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

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

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

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

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

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

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

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

    
156
        }
157

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

    
168
            if (!canUseFilter) {
169
                theQueryForProvider.setFilter(null);
170
            }
171

    
172
        }
173

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

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

    
200
    }
201

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

    
216
            }
217
        }
218
        return true;
219
    }
220

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

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

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

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

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

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

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

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

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

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

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

    
330
        try {
331
            while (iterator.hasNext()) {
332
                Feature feature = (Feature) iterator.next();
333
                this.featureToIgnoreNotification = feature;
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
    public DisposableIterator fastIterator() throws DataException {
354
        return this.fastIterator(0);
355
    }
356

    
357
    public DisposableIterator fastIterator(long index) throws DataException {
358
        if (index < 0) {
359
            throw new IndexOutOfBoundsException("The index (" + index
360
                + ") is less than 0");
361
        }
362
        int mode = this.getIteratorMode();
363

    
364
        switch (mode) {
365
        case DEFAULT:
366
            return new FastDefaultIterator(this, index);
367

    
368
        case FILTERED:
369
            return new FastFilteredIterator(this, index);
370

    
371
        case ORDERED:
372
            if (this.orderedData != null) {
373
                return new FastOrderedIterator(this, index);
374
            } else {
375
                return new FastOrderedIterator(this, new FastDefaultIterator(
376
                    this, 0), index);
377
            }
378

    
379
        case ORDERED_FILTERED:
380
            if (this.orderedData != null) {
381
                return new FastOrderedIterator(this, index);
382
            } else {
383
                return new FastOrderedIterator(this, new FastFilteredIterator(
384
                    this, 0), index);
385
            }
386

    
387
        case EDITED:
388
            return new FastEditedIterator(this, index);
389

    
390
        case EDITED_FILTERED:
391
            return new FastEditedFilteredIterator(this, index);
392

    
393
        case ORDERD_EDITED:
394
            if (this.orderedData != null) {
395
                return new FastOrderedIterator(this, index);
396
            } else {
397
                return new FastOrderedIterator(this, new FastEditedIterator(
398
                    this, 0), index);
399
            }
400

    
401
        case ORDERED_EDITED_FILTER:
402
            if (this.orderedData != null) {
403
                return new FastOrderedIterator(this, index);
404
            } else {
405
                return new FastOrderedIterator(this,
406
                    new FastEditedFilteredIterator(this, 0), index);
407
            }
408
        default:
409
            throw new IllegalArgumentException();
410
        }
411
    }
412

    
413
    public DisposableIterator iterator() {
414
        try {
415
            return this.fastIterator(0);
416
        } catch (DataException ex) {
417
            throw new RuntimeException("Can't obtain itertor.",ex);
418
        }
419
    }
420

    
421
    public DisposableIterator iterator(long index) throws DataException {
422
        if (index < 0) {
423
            throw new IndexOutOfBoundsException("The index (" + index
424
                + ") is less than 0");
425
        }
426
        int mode = this.getIteratorMode();
427

    
428
        switch (mode) {
429
        case DEFAULT:
430
            return new DefaultIterator(this, index);
431

    
432
        case FILTERED:
433
            return new FilteredIterator(this, index);
434

    
435
        case ORDERED:
436
            if (orderedData != null) {
437
                return new OrderedIterator(this, index);
438

    
439
            } else {
440
                return new OrderedIterator(this, new DefaultIterator(this, 0),
441
                    index);
442
            }
443

    
444
        case ORDERED_FILTERED:
445
            return new OrderedIterator(this, new FilteredIterator(this, 0),
446
                index);
447

    
448
        case EDITED:
449
            return new EditedIterator(this, index);
450

    
451
        case EDITED_FILTERED:
452
            return new EditedFilteredIterator(this, index);
453

    
454
        case ORDERD_EDITED:
455
            return new OrderedIterator(this, new EditedIterator(this, 0), index);
456

    
457
        case ORDERED_EDITED_FILTER:
458
            return new OrderedIterator(this,
459
                new EditedFilteredIterator(this, 0), index);
460

    
461
        default:
462
            throw new IllegalArgumentException();
463
        }
464

    
465
    }
466

    
467
    private boolean providerCanOrder() {
468
        return this.provider.canOrder();
469
    }
470

    
471
    private boolean providerCanFilter() {
472
        return this.provider.canFilter();
473
    }
474

    
475
    private int getIteratorMode() {
476

    
477
        if (this.iteratorMode != NO_CHECKED) {
478
            return this.iteratorMode;
479
        }
480

    
481
        // TODO Tener en cuenta las transformaciones ???
482

    
483
        if (store.isEditing() && store.getFeatureManager().hasChanges()) {
484
            if (this.query.hasOrder()) { // En edicion siempre ordeno yo.
485
                if (this.query.hasFilter()) {
486
                    return ORDERED_EDITED_FILTER;
487
                } else {
488
                    return ORDERD_EDITED;
489
                }
490
            } else {
491
                if (this.query.hasFilter()) {
492
                    return EDITED_FILTERED;
493
                } else {
494
                    return EDITED;
495
                }
496
            }
497
        } else {
498
            boolean useMyFilter = this.query.hasFilter();
499
            boolean useMyOrder = this.query.hasOrder();
500
            if (this.providerCanOrder() && this.transform.isEmpty()) {
501
                useMyOrder = false;
502
            }
503
            if (this.providerCanFilter() && this.transform.isEmpty()) {
504
                useMyFilter = false;
505
            }
506

    
507
            if (useMyOrder) {
508
                if (useMyFilter) {
509
                    return ORDERED_FILTERED;// ORDERED_FILTERED;
510
                } else {
511
                    return ORDERED;// ORDERED;
512
                }
513
            } else {
514
                if (useMyFilter) {
515
                    return FILTERED;// FILTERED;
516
                } else {
517
                    return DEFAULT;// DEFAULT;
518
                }
519
            }
520
        }
521

    
522
    }
523

    
524
    public void delete(Feature feature) throws DataException {
525
        this.featureToIgnoreNotification = feature;
526
        this.store.delete(feature);
527
        if (this.size > 0) {
528
            this.size--;
529
        }
530
        this.featureToIgnoreNotification = null;
531
        this.ownFeaturesModified = true;
532
    }
533

    
534
    public void insert(EditableFeature feature) throws DataException {
535
        this.featureToIgnoreNotification = feature;
536
        this.store.insert(feature);
537
        if (this.size >= 0) {
538
            this.size++;
539
        }
540
        this.featureToIgnoreNotification = null;
541
        this.ownFeaturesModified = true;
542
    }
543

    
544
    public void update(EditableFeature feature) throws DataException {
545
        this.featureToIgnoreNotification = feature;
546
        this.store.update(feature);
547
        this.featureToIgnoreNotification = null;
548
        this.ownFeaturesModified = true;
549
    }
550

    
551
    public DynObjectSet getDynObjectSet() {
552
        return this.getDynObjectSet(true);
553
    }
554

    
555
    public DynObjectSet getDynObjectSet(boolean fast) {
556
        return new DynObjectSetFeatureSetFacade(this, store, fast);
557
    }
558

    
559
    public FeatureStore getFeatureStore() {
560
        return store;
561
    }
562
}