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

History | View | Annotate | Download (18.7 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.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.clearAttributeNames();
143
        FeatureType ftype =
144
            transformsToUse.getSourceFeatureTypeFrom(this.defatulFeatureType);
145
        theQueryForProvider.setFeatureTypeId(ftype.getId());
146
        this.defatulFeatureTypeForProvider = ftype;
147

    
148
        if (transformsToUse.isTransformsOriginalValues()) {
149
            theQueryForProvider.clearFilter();
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.clearFilter();
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
                visitor.visit(feature);
334
            }
335
        } finally {
336
            iterator.dispose();
337
        }
338
    }
339

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

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

    
352
    public DisposableIterator fastIterator() throws DataException {
353
        return this.fastIterator(0);
354
    }
355

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
464
    }
465

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

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

    
474
    private int getIteratorMode() {
475

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

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

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

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

    
521
    }
522

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

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

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

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

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

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