Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_dal / src / org / gvsig / fmap / dal / feature / impl / featureset / DefaultFeatureSet.java @ 38417

History | View | Annotate | Download (18.4 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.FeatureQueryOrderMember;
37
import org.gvsig.fmap.dal.feature.FeatureSet;
38
import org.gvsig.fmap.dal.feature.FeatureStore;
39
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
40
import org.gvsig.fmap.dal.feature.FeatureType;
41
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
42
import org.gvsig.fmap.dal.feature.exception.FeatureSetInitializeException;
43
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureStore;
44
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureStoreTransforms;
45
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
46
import org.gvsig.tools.dispose.DisposableIterator;
47
import org.gvsig.tools.dynobject.DynObjectSet;
48
import org.gvsig.tools.evaluator.Evaluator;
49
import org.gvsig.tools.exception.BaseException;
50
import org.gvsig.tools.observer.Observable;
51
import org.gvsig.tools.observer.Observer;
52
import org.gvsig.tools.visitor.VisitCanceledException;
53
import org.gvsig.tools.visitor.Visitor;
54
import org.gvsig.tools.visitor.impl.AbstractIndexedVisitable;
55

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

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

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

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

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

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

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

    
144
        if (transformsToUse.isTransformsOriginalValues()) {
145
            theQueryForProvider.setFilter(null);
146
            theQueryForProvider.getOrder().clear();
147
            return;
148

    
149
        }
150

    
151
        // Filter
152
        Evaluator filter = theQueryForProvider.getFilter();
153
        if (filter != null) {
154
            boolean canUseFilter = true;
155
            if (filter.getFieldsInfo() == null) {
156
                canUseFilter = false;
157
            } else {
158
                canUseFilter = areEvaluatorFieldsInAttributes(filter, ftype);
159
            }
160

    
161
            if (!canUseFilter) {
162
                theQueryForProvider.setFilter(null);
163
            }
164

    
165
        }
166

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

    
188
            if (!canUseOrder) {
189
                theQueryForProvider.getOrder().clear();
190
            }
191
        }
192

    
193
    }
194

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

    
209
            }
210
        }
211
        return true;
212
    }
213

    
214
    public FeatureType getDefaultFeatureType() {
215
        return this.defatulFeatureType;
216
    }
217

    
218
    public List getFeatureTypes() {
219
        return Collections.unmodifiableList(this.featureTypes);
220
    }
221

    
222
    public long getSize() throws DataException {
223
        this.checkSourceStoreModified();
224
        if (size < 0) {
225
            size = calculateSize();
226
        }
227
        return size;
228
    }
229

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

    
259
    public void dispose() {
260
        this.store.deleteObserver(this);
261
        this.provider.dispose();
262
        this.provider = null;
263

    
264
        this.featureToIgnoreNotification = null;
265
        if (orderedData != null) {
266
            orderedData.clear();
267
        }
268
        this.orderedData = null;
269
        this.store = null;
270
        this.transform = null;
271
        this.query = null;
272
        this.queryForProvider = null;
273
        this.featureTypes = null;
274
        this.defatulFeatureType = null;
275
        this.defatulFeatureTypeForProvider = null;
276
    }
277

    
278
    public boolean isFromStore(DataStore store) {
279
        return this.store.equals(store);
280
    }
281

    
282
    public void update(Observable obsevable, Object notification) {
283
        if (sourceStoreModified) {
284
            return;
285
        }
286

    
287
        String type = ((FeatureStoreNotification) notification).getType();
288

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

    
319
    protected void doAccept(Visitor visitor, long firstValueIndex)
320
        throws VisitCanceledException, BaseException {
321
        DisposableIterator iterator = fastIterator(firstValueIndex);
322

    
323
        try {
324
            while (iterator.hasNext()) {
325
                Feature feature = (Feature) iterator.next();
326
                visitor.visit(feature);
327
            }
328
        } finally {
329
            iterator.dispose();
330
        }
331
    }
332

    
333
    protected void checkSourceStoreModified() {
334
        if (sourceStoreModified) {
335
                        throw new ConcurrentDataModificationException(store == null ? ""
336
                                        : store.getName());
337
        }
338
    }
339

    
340
    public boolean isEmpty() throws DataException {
341
        checkSourceStoreModified();
342
        return this.getSize() == 0;
343
    }
344

    
345
    public DisposableIterator fastIterator() throws DataException {
346
        return this.fastIterator(0);
347
    }
348

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

    
356
        switch (mode) {
357
        case DEFAULT:
358
            return new FastDefaultIterator(this, index);
359

    
360
        case FILTERED:
361
            return new FastFilteredIterator(this, index);
362

    
363
        case ORDERED:
364
            if (this.orderedData != null) {
365
                return new FastOrderedIterator(this, index);
366
            } else {
367
                return new FastOrderedIterator(this, new FastDefaultIterator(
368
                    this, 0), index);
369
            }
370

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

    
379
        case EDITED:
380
            return new FastEditedIterator(this, index);
381

    
382
        case EDITED_FILTERED:
383
            return new FastEditedFilteredIterator(this, index);
384

    
385
        case ORDERD_EDITED:
386
            if (this.orderedData != null) {
387
                return new FastOrderedIterator(this, index);
388
            } else {
389
                return new FastOrderedIterator(this, new FastEditedIterator(
390
                    this, 0), index);
391
            }
392

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

    
405
    public DisposableIterator iterator() throws DataException {
406
        return this.iterator(0);
407
    }
408

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

    
416
        switch (mode) {
417
        case DEFAULT:
418
            return new DefaultIterator(this, index);
419

    
420
        case FILTERED:
421
            return new FilteredIterator(this, index);
422

    
423
        case ORDERED:
424
            if (orderedData != null) {
425
                return new OrderedIterator(this, index);
426

    
427
            } else {
428
                return new OrderedIterator(this, new DefaultIterator(this, 0),
429
                    index);
430
            }
431

    
432
        case ORDERED_FILTERED:
433
            return new OrderedIterator(this, new FilteredIterator(this, 0),
434
                index);
435

    
436
        case EDITED:
437
            return new EditedIterator(this, index);
438

    
439
        case EDITED_FILTERED:
440
            return new EditedFilteredIterator(this, index);
441

    
442
        case ORDERD_EDITED:
443
            return new OrderedIterator(this, new EditedIterator(this, 0), index);
444

    
445
        case ORDERED_EDITED_FILTER:
446
            return new OrderedIterator(this,
447
                new EditedFilteredIterator(this, 0), index);
448

    
449
        default:
450
            throw new IllegalArgumentException();
451
        }
452

    
453
    }
454

    
455
    private boolean providerCanOrder() {
456
        return this.provider.canOrder();
457
    }
458

    
459
    private boolean providerCanFilter() {
460
        return this.provider.canFilter();
461
    }
462

    
463
    private int getIteratorMode() {
464

    
465
        if (this.iteratorMode != NO_CHECKED) {
466
            return this.iteratorMode;
467
        }
468

    
469
        // TODO Tener en cuenta las transformaciones ???
470

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

    
495
            if (useMyOrder) {
496
                if (useMyFilter) {
497
                    return ORDERED_FILTERED;// ORDERED_FILTERED;
498
                } else {
499
                    return ORDERED;// ORDERED;
500
                }
501
            } else {
502
                if (useMyFilter) {
503
                    return FILTERED;// FILTERED;
504
                } else {
505
                    return DEFAULT;// DEFAULT;
506
                }
507
            }
508
        }
509

    
510
    }
511

    
512
    public void delete(Feature feature) throws DataException {
513
        this.featureToIgnoreNotification = feature;
514
        this.store.delete(feature);
515
        if (this.size > 0) {
516
            this.size--;
517
        }
518
        this.featureToIgnoreNotification = null;
519
        this.ownFeaturesModified = true;
520
    }
521

    
522
    public void insert(EditableFeature feature) throws DataException {
523
        this.featureToIgnoreNotification = feature;
524
        this.store.insert(feature);
525
        if (this.size >= 0) {
526
            this.size++;
527
        }
528
        this.featureToIgnoreNotification = null;
529
        this.ownFeaturesModified = true;
530
    }
531

    
532
    public void update(EditableFeature feature) throws DataException {
533
        this.featureToIgnoreNotification = feature;
534
        this.store.update(feature);
535
        this.featureToIgnoreNotification = null;
536
        this.ownFeaturesModified = true;
537
    }
538

    
539
    public DynObjectSet getDynObjectSet() {
540
        return this.getDynObjectSet(true);
541
    }
542

    
543
    public DynObjectSet getDynObjectSet(boolean fast) {
544
        return new DynObjectSetFeatureSetFacade(this, store, fast);
545
    }
546

    
547
    public FeatureStore getFeatureStore() {
548
        return store;
549
    }
550
}