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

History | View | Annotate | Download (18.5 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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 2
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
 */
22
package org.gvsig.fmap.dal.feature.impl.featureset;
23

    
24
import java.util.ArrayList;
25
import java.util.Collections;
26
import java.util.Iterator;
27
import java.util.List;
28
import java.util.NoSuchElementException;
29

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

    
57
public class DefaultFeatureSet extends AbstractIndexedVisitable implements
58
    FeatureSet, Observer {
59

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

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

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

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

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

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

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

    
153
        }
154

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

    
165
            if (!canUseFilter) {
166
                theQueryForProvider.setFilter(null);
167
            }
168

    
169
        }
170

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

    
192
            if (!canUseOrder) {
193
                theQueryForProvider.getOrder().clear();
194
            }
195
        }
196

    
197
    }
198

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

    
213
            }
214
        }
215
        return true;
216
    }
217

    
218
    public FeatureType getDefaultFeatureType() {
219
        return this.defatulFeatureType;
220
    }
221

    
222
    public List getFeatureTypes() {
223
        return Collections.unmodifiableList(this.featureTypes);
224
    }
225

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

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

    
263
    public void dispose() {
264
        this.store.deleteObserver(this);
265
        this.provider.dispose();
266
        this.provider = null;
267

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

    
282
    public boolean isFromStore(DataStore store) {
283
        return this.store.equals(store);
284
    }
285

    
286
    public void update(Observable obsevable, Object notification) {
287
        if (sourceStoreModified) {
288
            return;
289
        }
290

    
291
        String type = ((FeatureStoreNotification) notification).getType();
292

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

    
323
    protected void doAccept(Visitor visitor, long firstValueIndex)
324
        throws VisitCanceledException, BaseException {
325
        DisposableIterator iterator = fastIterator(firstValueIndex);
326

    
327
        try {
328
            while (iterator.hasNext()) {
329
                Feature feature = (Feature) iterator.next();
330
                visitor.visit(feature);
331
            }
332
        } finally {
333
            iterator.dispose();
334
        }
335
    }
336

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

    
344
    public boolean isEmpty() throws DataException {
345
        checkSourceStoreModified();
346
        return this.getSize() == 0;
347
    }
348

    
349
    public DisposableIterator fastIterator() throws DataException {
350
        return this.fastIterator(0);
351
    }
352

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

    
360
        switch (mode) {
361
        case DEFAULT:
362
            return new FastDefaultIterator(this, index);
363

    
364
        case FILTERED:
365
            return new FastFilteredIterator(this, index);
366

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

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

    
383
        case EDITED:
384
            return new FastEditedIterator(this, index);
385

    
386
        case EDITED_FILTERED:
387
            return new FastEditedFilteredIterator(this, index);
388

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

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

    
409
    public DisposableIterator iterator() throws DataException {
410
        return this.iterator(0);
411
    }
412

    
413
    public DisposableIterator iterator(long index) throws DataException {
414
        if (index < 0) {
415
            throw new IndexOutOfBoundsException("The index (" + index
416
                + ") is less than 0");
417
        }
418
        int mode = this.getIteratorMode();
419

    
420
        switch (mode) {
421
        case DEFAULT:
422
            return new DefaultIterator(this, index);
423

    
424
        case FILTERED:
425
            return new FilteredIterator(this, index);
426

    
427
        case ORDERED:
428
            if (orderedData != null) {
429
                return new OrderedIterator(this, index);
430

    
431
            } else {
432
                return new OrderedIterator(this, new DefaultIterator(this, 0),
433
                    index);
434
            }
435

    
436
        case ORDERED_FILTERED:
437
            return new OrderedIterator(this, new FilteredIterator(this, 0),
438
                index);
439

    
440
        case EDITED:
441
            return new EditedIterator(this, index);
442

    
443
        case EDITED_FILTERED:
444
            return new EditedFilteredIterator(this, index);
445

    
446
        case ORDERD_EDITED:
447
            return new OrderedIterator(this, new EditedIterator(this, 0), index);
448

    
449
        case ORDERED_EDITED_FILTER:
450
            return new OrderedIterator(this,
451
                new EditedFilteredIterator(this, 0), index);
452

    
453
        default:
454
            throw new IllegalArgumentException();
455
        }
456

    
457
    }
458

    
459
    private boolean providerCanOrder() {
460
        return this.provider.canOrder();
461
    }
462

    
463
    private boolean providerCanFilter() {
464
        return this.provider.canFilter();
465
    }
466

    
467
    private int getIteratorMode() {
468

    
469
        if (this.iteratorMode != NO_CHECKED) {
470
            return this.iteratorMode;
471
        }
472

    
473
        // TODO Tener en cuenta las transformaciones ???
474

    
475
        if (store.isEditing() && store.getFeatureManager().hasChanges()) {
476
            if (this.query.hasOrder()) { // En edicion siempre ordeno yo.
477
                if (this.query.hasFilter()) {
478
                    return ORDERED_EDITED_FILTER;
479
                } else {
480
                    return ORDERD_EDITED;
481
                }
482
            } else {
483
                if (this.query.hasFilter()) {
484
                    return EDITED_FILTERED;
485
                } else {
486
                    return EDITED;
487
                }
488
            }
489
        } else {
490
            boolean useMyFilter = this.query.hasFilter();
491
            boolean useMyOrder = this.query.hasOrder();
492
            if (this.providerCanOrder() && this.transform.isEmpty()) {
493
                useMyOrder = false;
494
            }
495
            if (this.providerCanFilter() && this.transform.isEmpty()) {
496
                useMyFilter = false;
497
            }
498

    
499
            if (useMyOrder) {
500
                if (useMyFilter) {
501
                    return ORDERED_FILTERED;// ORDERED_FILTERED;
502
                } else {
503
                    return ORDERED;// ORDERED;
504
                }
505
            } else {
506
                if (useMyFilter) {
507
                    return FILTERED;// FILTERED;
508
                } else {
509
                    return DEFAULT;// DEFAULT;
510
                }
511
            }
512
        }
513

    
514
    }
515

    
516
    public void delete(Feature feature) throws DataException {
517
        this.featureToIgnoreNotification = feature;
518
        this.store.delete(feature);
519
        if (this.size > 0) {
520
            this.size--;
521
        }
522
        this.featureToIgnoreNotification = null;
523
        this.ownFeaturesModified = true;
524
    }
525

    
526
    public void insert(EditableFeature feature) throws DataException {
527
        this.featureToIgnoreNotification = feature;
528
        this.store.insert(feature);
529
        if (this.size >= 0) {
530
            this.size++;
531
        }
532
        this.featureToIgnoreNotification = null;
533
        this.ownFeaturesModified = true;
534
    }
535

    
536
    public void update(EditableFeature feature) throws DataException {
537
        this.featureToIgnoreNotification = feature;
538
        this.store.update(feature);
539
        this.featureToIgnoreNotification = null;
540
        this.ownFeaturesModified = true;
541
    }
542

    
543
    public DynObjectSet getDynObjectSet() {
544
        return this.getDynObjectSet(true);
545
    }
546

    
547
    public DynObjectSet getDynObjectSet(boolean fast) {
548
        return new DynObjectSetFeatureSetFacade(this, store, fast);
549
    }
550

    
551
    public FeatureStore getFeatureStore() {
552
        return store;
553
    }
554
}