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

History | View | Annotate | Download (19.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.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

    
59
public class DefaultFeatureSet extends AbstractFeatureSet implements
60
    FeatureSet, Observer {
61

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

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

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

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

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

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

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

    
155
        }
156

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

    
167
            if (!canUseFilter) {
168
                theQueryForProvider.clearFilter();
169
            }
170

    
171
        }
172

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

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

    
199
    }
200

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

    
215
            }
216
        }
217
        return true;
218
    }
219

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

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

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

    
236
    private long calculateSize() throws DataException {
237
        int mode = this.getIteratorMode();
238
        long limit = this.query.getLimit();
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 ((limit>0 && (mySize<limit)) || limit==0 ) {
250
                    iter.next();
251
                    mySize++;
252
                }
253
            } catch (NoSuchElementException e) {
254
                return mySize;
255
            } finally {
256
                iter.dispose();
257
            }
258
        } else if ((mode & EDITED) == EDITED) {
259
            long mySize = provider.getSize()
260
                + store.getFeatureManager().getDeltaSize();
261
            return (limit>0 && mySize>limit)? limit:mySize;
262
        }
263
        long mySize = provider.getSize();
264
        return (limit>0 && mySize>limit)? limit:mySize;
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 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 checkSourceStoreModified() {
324
        if (sourceStoreModified) {
325
                        throw new ConcurrentDataModificationException(store == null ? ""
326
                                        : store.getName());
327
        }
328
    }
329

    
330
    @Override
331
    public DisposableIterator fastIterator(long index) throws DataException {
332
        return fastIterator(index, 0);
333
    }
334
    
335
    @Override
336
    public DisposableIterator fastIterator(long index, long elements) throws DataException {
337
        if (index < 0) {
338
            throw new IndexOutOfBoundsException("The index (" + index
339
                + ") is less than 0");
340
        }
341
        DisposableIterator it;
342
        int mode = this.getIteratorMode();
343

    
344
        switch (mode) {
345
        case DEFAULT:
346
            it = new FastDefaultIterator(this, index, elements);
347
            break;
348

    
349
        case FILTERED:
350
            it = new FastFilteredIterator(this, index);
351
            break;
352

    
353
        case ORDERED:
354
            if (this.orderedData != null) {
355
                it = new FastOrderedIterator(this, index);
356
            } else {
357
                it = new FastOrderedIterator(this, new FastDefaultIterator(this, 0, elements), index);
358
            }
359
            break;
360
            
361
        case ORDERED_FILTERED:
362
            if (this.orderedData != null) {
363
                it = new FastOrderedIterator(this, index);
364
            } else {
365
                it = new FastOrderedIterator(this, new FastFilteredIterator(
366
                    this, 0), index);
367
            }
368
            break;
369

    
370
        case EDITED:
371
            it = new FastEditedIterator(this, index);
372
            break;
373

    
374
        case EDITED_FILTERED:
375
            it = new FastEditedFilteredIterator(this, index);
376
            break;
377

    
378
        case ORDERD_EDITED:
379
            if (this.orderedData != null) {
380
                it = new FastOrderedIterator(this, index);
381
            } else {
382
                it = new FastOrderedIterator(this, new FastEditedIterator(
383
                    this, 0), index);
384
            }
385
            break;
386

    
387
        case ORDERED_EDITED_FILTER:
388
            if (this.orderedData != null) {
389
                it = new FastOrderedIterator(this, index);
390
            } else {
391
                it = new FastOrderedIterator(this,
392
                    new FastEditedFilteredIterator(this, 0), index);
393
            }
394
            break;
395
            
396
        default:
397
            throw new IllegalArgumentException();
398
        }
399
        if( this.query!=null && this.query.getLimit()>0 ) {
400
            it = new LimitIterator(it,this.query.getLimit());
401
        }
402
        return it;
403
    }
404

    
405
    private class LimitIterator implements DisposableIterator {
406

    
407
        private final DisposableIterator it;
408
        private final long limit;
409
        private int count;
410

    
411
        private LimitIterator(DisposableIterator it, long limit) {
412
            this.it = it;
413
            this.limit = limit;
414
            this.count = 0;
415
        }
416

    
417
        @Override
418
        public void dispose() {
419
            this.it.dispose();
420
        }
421

    
422
        @Override
423
        public boolean hasNext() {
424
            if( this.count>=this.limit ) {
425
                return false;
426
            }
427
            return this.it.hasNext();
428
        }
429

    
430
        @Override
431
        public Object next() {
432
            if( this.count>=this.limit ) {
433
                return null;
434
            }
435
            this.count++;
436
            return this.it.next();
437
        }
438

    
439
        @Override
440
        public void remove() {
441
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
442
        }
443
        
444
    }
445

    
446
    @Override
447
    public DisposableIterator iterator(long index) throws DataException {
448
        return iterator(index,0);
449
    }
450
    
451
    @Override
452
    public DisposableIterator iterator(long index, long elements) throws DataException {        
453
        if (index < 0) {
454
            throw new IndexOutOfBoundsException("The index (" + index
455
                + ") is less than 0");
456
        }
457
        DisposableIterator it;
458
        int mode = this.getIteratorMode();
459

    
460
        switch (mode) {
461
        case DEFAULT:
462
            it = new DefaultIterator(this, index, elements);
463
            break;
464

    
465
        case FILTERED:
466
            it = new FilteredIterator(this, index);
467
            break;
468

    
469
        case ORDERED:
470
            if (orderedData != null) {
471
                it = new OrderedIterator(this, index);
472

    
473
            } else {
474
                it = new OrderedIterator(this, new DefaultIterator(this, 0, elements),index);
475
            }
476
            break;
477

    
478
        case ORDERED_FILTERED:
479
            it = new OrderedIterator(this, new FilteredIterator(this, 0),
480
                index);
481
            break;
482

    
483
        case EDITED:
484
            it = new EditedIterator(this, index);
485
            break;
486

    
487
        case EDITED_FILTERED:
488
            it = new EditedFilteredIterator(this, index);
489
            break;
490

    
491
        case ORDERD_EDITED:
492
            it = new OrderedIterator(this, new EditedIterator(this, 0), index);
493
            break;
494

    
495
        case ORDERED_EDITED_FILTER:
496
            it = new OrderedIterator(this,
497
                new EditedFilteredIterator(this, 0), index);
498
            break;
499

    
500
        default:
501
            throw new IllegalArgumentException();
502
        }
503

    
504
        if( this.query!=null && this.query.getLimit()>0 ) {
505
            it = new LimitIterator(it,this.query.getLimit());
506
        }
507
        return it;
508
    }
509

    
510
    private boolean providerCanOrder() {
511
        return this.provider.canOrder();
512
    }
513

    
514
    private boolean providerCanFilter() {
515
        return this.provider.canFilter();
516
    }
517

    
518
    private int getIteratorMode() {
519

    
520
        if (this.iteratorMode != NO_CHECKED) {
521
            return this.iteratorMode;
522
        }
523

    
524
        // TODO Tener en cuenta las transformaciones ???
525

    
526
        if (store.isEditing() && (store.getFeatureTypeManager().hasChanges() || store.getFeatureManager().hasChanges())) {
527
            if (this.query.hasOrder()) { // En edicion siempre ordeno yo.
528
                if (this.query.hasFilter()) {
529
                    return ORDERED_EDITED_FILTER;
530
                } else {
531
                    return ORDERD_EDITED;
532
                }
533
            } else {
534
                if (this.query.hasFilter()) {
535
                    return EDITED_FILTERED;
536
                } else {
537
                    return EDITED;
538
                }
539
            }
540
        } else {
541
            boolean useMyFilter = this.query.hasFilter();
542
            boolean useMyOrder = this.query.hasOrder();
543
            if (this.providerCanOrder() && this.transform.isEmpty()) {
544
                useMyOrder = false;
545
            }
546
            if (this.providerCanFilter() && this.transform.isEmpty()) {
547
                useMyFilter = false;
548
            }
549

    
550
            if (useMyOrder) {
551
                if (useMyFilter) {
552
                    return ORDERED_FILTERED;// ORDERED_FILTERED;
553
                } else {
554
                    return ORDERED;// ORDERED;
555
                }
556
            } else {
557
                if (useMyFilter) {
558
                    return FILTERED;// FILTERED;
559
                } else {
560
                    return DEFAULT;// DEFAULT;
561
                }
562
            }
563
        }
564

    
565
    }
566

    
567
    public void delete(Feature feature) throws DataException {
568
        this.featureToIgnoreNotification = feature;
569
        this.store.delete(feature);
570
        if (this.size > 0) {
571
            this.size--;
572
        }
573
        this.featureToIgnoreNotification = null;
574
        this.ownFeaturesModified = true;
575
    }
576

    
577
    public void insert(EditableFeature feature) throws DataException {
578
        this.featureToIgnoreNotification = feature;
579
        this.store.insert(feature);
580
        if (this.size >= 0) {
581
            this.size++;
582
        }
583
        this.featureToIgnoreNotification = null;
584
        this.ownFeaturesModified = true;
585
    }
586

    
587
    public void update(EditableFeature feature) throws DataException {
588
        this.featureToIgnoreNotification = feature;
589
        this.store.update(feature);
590
        this.featureToIgnoreNotification = null;
591
        this.ownFeaturesModified = true;
592
    }
593

    
594
    public FeatureStore getFeatureStore() {
595
        return store;
596
    }
597

    
598
}