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

History | View | Annotate | Download (20.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 java.util.ArrayList;
27
import java.util.Collections;
28
import java.util.Iterator;
29
import java.util.List;
30
import java.util.NoSuchElementException;
31

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

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

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

    
69
    protected boolean sourceStoreModified;
70
    protected boolean ownFeaturesModified;
71
    protected DefaultFeatureStore store;
72
    protected List featureTypes;
73
    protected FeatureQuery query;
74
    protected FeatureSetProvider provider;
75
    protected long size;
76
    protected int iteratorMode;
77
    protected List orderedData;
78
    protected Feature featureToIgnoreNotification;
79
    protected DefaultFeatureStoreTransforms transform;
80
    protected FeatureQuery queryForProvider;
81
    protected FeatureType defaultFeatureType;
82
    protected FeatureType defatulFeatureTypeForProvider;
83
    protected boolean ignoreChanges;
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.defaultFeatureType = this.store.getDefaultFeatureType();
111
            this.featureTypes.addAll(this.store.getFeatureTypes());
112
        } else {
113
            this.defaultFeatureType = this.store.getFeatureType(this.query);
114
            List<EditableFeatureAttributeDescriptor> cols = this.query.getExtraColumn().getColumns();
115
            if (this.query!=null && cols!=null && !cols.isEmpty()) {
116
                DefaultFeatureType featureTypeExtraCols = (DefaultFeatureType) this.defaultFeatureType.getCopy();
117
                featureTypeExtraCols.setExtraColumn(this.query.getExtraColumn());
118
                this.defaultFeatureType = featureTypeExtraCols;
119
            }
120
            this.featureTypes.add(this.defaultFeatureType);
121
        }
122
        if (this.transform != null && !this.transform.isEmpty()) {
123
            this.fixQueryForProvider(this.queryForProvider, this.transform);
124
        } else {
125
            this.defatulFeatureTypeForProvider = this.defaultFeatureType;
126
        }
127

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

    
143
    private void fixQueryForProvider(FeatureQuery theQueryForProvider,
144
        DefaultFeatureStoreTransforms transformsToUse) throws DataException {
145
        theQueryForProvider.clearAttributeNames();
146
        FeatureType ftype =
147
            transformsToUse.getSourceFeatureTypeFrom(this.defaultFeatureType);
148
        theQueryForProvider.setFeatureTypeId(ftype.getId());
149
        this.defatulFeatureTypeForProvider = ftype;
150
        
151
        if (transformsToUse.isTransformsOriginalValues()) {
152
            theQueryForProvider.clearFilter();
153
            FeatureQueryOrder fqo = theQueryForProvider.getOrder();
154
            if (fqo != null) {
155
                fqo.clear();
156
            }
157
            return;
158

    
159
        }
160

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

    
171
            if (!canUseFilter) {
172
                theQueryForProvider.clearFilter();
173
            }
174

    
175
        }
176

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

    
198
            if (!canUseOrder) {
199
                theQueryForProvider.getOrder().clear();
200
            }
201
        }
202

    
203
    }
204

    
205
    private boolean areEvaluatorFieldsInAttributes(Evaluator evaluator,
206
        FeatureType fType) {
207
        if (evaluator.getFieldsInfo() == null) {
208
            return false;
209
        }
210
        String[] fieldNames = evaluator.getFieldsInfo().getFieldNames();
211
        if (fieldNames.length == 0) {
212
            return false;
213
        } else {
214
            for (String fieldName : fieldNames) {
215
                if (fType.get(fieldName) == null) {
216
                    return false;
217
                }
218
            }
219
        }
220
        return true;
221
    }
222

    
223
    @Override
224
    public FeatureType getDefaultFeatureType() {
225
        return this.defaultFeatureType;
226
    }
227

    
228
    @Override
229
    public List getFeatureTypes() {
230
        return Collections.unmodifiableList(this.featureTypes);
231
    }
232

    
233
    @Override
234
    public long getSize() throws DataException {
235
        this.checkSourceStoreModified();
236
        if (size < 0) {
237
            size = calculateSize();
238
        }
239
        return size;
240
    }
241

    
242
    private long calculateSize() throws DataException {
243
        long limit = this.query.getLimit();
244
        long mySize = 0;
245
        
246
        int mode = this.getIteratorMode();
247
        switch (mode) {
248
        case DEFAULT:
249
        case ORDERED:
250
            if (this.provider.isEmpty()) {
251
                return 0;
252
            }
253
            mySize = provider.getSize();
254
            return (limit>0 && mySize>limit)? limit:mySize;
255

    
256
        case FILTERED:
257
        case ORDERED_FILTERED:
258
            DisposableIterator iter = null;
259
            try {
260
                iter = this.fastIterator();
261
                while ((limit>0 && (mySize<limit)) || limit==0 ) {
262
                    iter.next();
263
                    mySize++;
264
                }
265
            } catch (NoSuchElementException e) {
266

    
267
            } finally {
268
                DisposeUtils.disposeQuietly(iter);
269
            }
270
            return mySize;
271

    
272
        case EDITED:
273
        case EDITED_FILTERED:
274
        case ORDERD_EDITED:
275
        case ORDERED_EDITED_FILTER:
276
            mySize = provider.getSize()
277
                + store.getFeatureManager().getDeltaSize();
278
            return (limit>0 && mySize>limit)? limit:mySize;
279

    
280
        default:
281
            throw new IllegalArgumentException();
282
        }
283
    }
284

    
285
    public void dispose() {
286
        if( this.store!=null ) {
287
            this.store.deleteObserver(this);
288
            this.store = null;
289
        }
290
        if( this.provider!=null ) {
291
            this.provider.dispose();
292
            this.provider = null;
293
        }
294
        if (orderedData != null) {
295
            orderedData.clear();
296
            this.orderedData = null;
297
        }
298
        this.featureToIgnoreNotification = null;
299
        this.transform = null;
300
        this.query = null;
301
        this.queryForProvider = null;
302
        this.featureTypes = null;
303
        this.defaultFeatureType = null;
304
        this.defatulFeatureTypeForProvider = null;
305
    }
306

    
307
    public void update(Observable obsevable, Object notification) {
308
        if (sourceStoreModified) {
309
            return;
310
        }
311

    
312
        String type = ((FeatureStoreNotification) notification).getType();
313

    
314
        if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_INSERT)
315
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_DELETE)
316
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UPDATE)) {
317
            if (this.featureToIgnoreNotification == ((FeatureStoreNotification) notification)
318
                .getFeature()) {
319
                return;
320
            }
321
            sourceStoreModified = true;
322
            return;
323
        }
324
        if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UPDATE_TYPE)
325
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_REDO)
326
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UNDO)
327
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_REFRESH)
328
            || type
329
                .equalsIgnoreCase(FeatureStoreNotification.COMPLEX_NOTIFICATION)
330
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_CLOSE)
331
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_DISPOSE)
332
            || type.equalsIgnoreCase(FeatureStoreNotification.TRANSFORM_CHANGE)) {
333
            sourceStoreModified = true;
334
            return;
335
        }
336
        if (type.equalsIgnoreCase(FeatureStoreNotification.RESOURCE_CHANGED)) {
337
            if(!this.ignoreChanges) {
338
                sourceStoreModified = true;
339
                return;
340
            }
341
        }
342
        if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_CANCELEDITING)) {
343
            if (ownFeaturesModified) {
344
                sourceStoreModified = true;
345
                return;
346
            }
347
        }
348
    }
349
  
350
    protected void checkSourceStoreModified() {
351
        if (sourceStoreModified) {
352
                        throw new ConcurrentDataModificationException(store == null ? ""
353
                                        : store.getName());
354
        }
355
    }
356

    
357
    @Override
358
    public DisposableIterator fastIterator(long index) throws DataException {
359
        return fastIterator(index, 0);
360
    }
361
    
362
    @Override
363
    public DisposableIterator fastIterator(long index, long elements) throws DataException {
364
        if (index < 0) {
365
            throw new IndexOutOfBoundsException("The index (" + index
366
                + ") is less than 0");
367
        }
368
        DisposableIterator it;
369
        int mode = this.getIteratorMode();
370

    
371
        switch (mode) {
372
        case DEFAULT:
373
            it = new FastDefaultIterator(this, index, elements);
374
            break;
375

    
376
        case FILTERED:
377
            it = new FastFilteredIterator(this, index);
378
            break;
379

    
380
        case ORDERED:
381
            if (this.orderedData != null) {
382
                it = new FastOrderedIterator(this, index);
383
            } else {
384
                it = new FastOrderedIterator(this, new FastDefaultIterator(this, 0, elements), index);
385
            }
386
            break;
387
            
388
        case ORDERED_FILTERED:
389
            if (this.orderedData != null) {
390
                it = new FastOrderedIterator(this, index);
391
            } else {
392
                it = new FastOrderedIterator(this, new FastFilteredIterator(
393
                    this, 0), index);
394
            }
395
            break;
396

    
397
        case EDITED:
398
            it = new FastEditedIterator(this, index);
399
            break;
400

    
401
        case EDITED_FILTERED:
402
            it = new FastEditedFilteredIterator(this, index);
403
            break;
404

    
405
        case ORDERD_EDITED:
406
            if (this.orderedData != null) {
407
                it = new FastOrderedIterator(this, index);
408
            } else {
409
                it = new FastOrderedIterator(this, new FastEditedIterator(
410
                    this, 0), index);
411
            }
412
            break;
413

    
414
        case ORDERED_EDITED_FILTER:
415
            if (this.orderedData != null) {
416
                it = new FastOrderedIterator(this, index);
417
            } else {
418
                it = new FastOrderedIterator(this,
419
                    new FastEditedFilteredIterator(this, 0), index);
420
            }
421
            break;
422
            
423
        default:
424
            throw new IllegalArgumentException();
425
        }
426
        if( this.query!=null && this.query.getLimit()>0 ) {
427
            it = new LimitIterator(it,this.query.getLimit());
428
        }
429
        return it;
430
    }
431

    
432
    private class LimitIterator implements DisposableIterator {
433

    
434
        private final DisposableIterator it;
435
        private final long limit;
436
        private int count;
437

    
438
        private LimitIterator(DisposableIterator it, long limit) {
439
            this.it = it;
440
            this.limit = limit;
441
            this.count = 0;
442
        }
443

    
444
        @Override
445
        public void dispose() {
446
            this.it.dispose();
447
        }
448

    
449
        @Override
450
        public boolean hasNext() {
451
            if( this.count>=this.limit ) {
452
                return false;
453
            }
454
            return this.it.hasNext();
455
        }
456

    
457
        @Override
458
        public Object next() {
459
            if( this.count>=this.limit ) {
460
                return null;
461
            }
462
            this.count++;
463
            return this.it.next();
464
        }
465

    
466
        @Override
467
        public void remove() {
468
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
469
        }
470
        
471
    }
472

    
473
    @Override
474
    public DisposableIterator iterator(long index) throws DataException {
475
        return iterator(index,0);
476
    }
477
    
478
    @Override
479
    public DisposableIterator iterator(long index, long elements) throws DataException {        
480
        if (index < 0) {
481
            throw new IndexOutOfBoundsException("The index (" + index
482
                + ") is less than 0");
483
        }
484
        DisposableIterator it;
485
        int mode = this.getIteratorMode();
486

    
487
        switch (mode) {
488
        case DEFAULT:
489
            it = new DefaultIterator(this, index, elements);
490
            break;
491

    
492
        case FILTERED:
493
            it = new FilteredIterator(this, index);
494
            break;
495

    
496
        case ORDERED:
497
            if (orderedData != null) {
498
                it = new OrderedIterator(this, index);
499

    
500
            } else {
501
                it = new OrderedIterator(this, new DefaultIterator(this, 0, elements),index);
502
            }
503
            break;
504

    
505
        case ORDERED_FILTERED:
506
            it = new OrderedIterator(this, new FilteredIterator(this, 0),
507
                index);
508
            break;
509

    
510
        case EDITED:
511
            it = new EditedIterator(this, index);
512
            break;
513

    
514
        case EDITED_FILTERED:
515
            it = new EditedFilteredIterator(this, index);
516
            break;
517

    
518
        case ORDERD_EDITED:
519
            it = new OrderedIterator(this, new EditedIterator(this, 0), index);
520
            break;
521

    
522
        case ORDERED_EDITED_FILTER:
523
            it = new OrderedIterator(this,
524
                new EditedFilteredIterator(this, 0), index);
525
            break;
526

    
527
        default:
528
            throw new IllegalArgumentException();
529
        }
530

    
531
        if( this.query!=null && this.query.getLimit()>0 ) {
532
            it = new LimitIterator(it,this.query.getLimit());
533
        }
534
        return it;
535
    }
536

    
537
    private boolean providerCanOrder() {
538
        return this.provider.canOrder();
539
    }
540

    
541
    private boolean providerCanFilter() {
542
        return this.provider.canFilter();
543
    }
544

    
545
    private int getIteratorMode() {
546

    
547
        if (this.iteratorMode != NO_CHECKED) {
548
            return this.iteratorMode;
549
        }
550

    
551
        // TODO Tener en cuenta las transformaciones ???
552

    
553
        if (store.isEditing() && (store.getFeatureTypeManager().hasChanges() || store.getFeatureManager().hasChanges())) {
554
            if (this.query.hasOrder()) { // En edicion siempre ordeno yo.
555
                if (this.query.hasFilter()) {
556
                    return ORDERED_EDITED_FILTER;
557
                } else {
558
                    return ORDERD_EDITED;
559
                }
560
            } else {
561
                if (this.query.hasFilter()) {
562
                    return EDITED_FILTERED;
563
                } else {
564
                    return EDITED;
565
                }
566
            }
567
        } else {
568
            boolean useMyFilter = this.query.hasFilter();
569
            boolean useMyOrder = this.query.hasOrder();
570
            if (this.providerCanOrder() && this.transform.isEmpty()) {
571
                useMyOrder = false;
572
            }
573
            if (this.providerCanFilter() && this.transform.isEmpty()) {
574
                useMyFilter = false;
575
            }
576

    
577
            if (useMyOrder) {
578
                if (useMyFilter) {
579
                    return ORDERED_FILTERED;
580
                } else {
581
                    return ORDERED;
582
                }
583
            } else {
584
                if (useMyFilter) {
585
                    return FILTERED;
586
                } else {
587
                    return DEFAULT;
588
                }
589
            }
590
        }
591

    
592
    }
593

    
594
    @Override
595
    public void delete(Feature feature) throws DataException {
596
        this.featureToIgnoreNotification = feature;
597
        this.store.delete(feature);
598
        if (this.size > 0) {
599
            this.size--;
600
        }
601
        this.featureToIgnoreNotification = null;
602
        this.ownFeaturesModified = true;
603
    }
604

    
605
    @Override
606
    public void insert(EditableFeature feature) throws DataException {
607
        this.featureToIgnoreNotification = feature;
608
        this.store.insert(feature);
609
        if (this.size >= 0) {
610
            this.size++;
611
        }
612
        this.featureToIgnoreNotification = null;
613
        this.ownFeaturesModified = true;
614
    }
615

    
616
    @Override
617
    public void update(EditableFeature feature) throws DataException {
618
        this.featureToIgnoreNotification = feature;
619
        this.store.update(feature);
620
        this.featureToIgnoreNotification = null;
621
        this.ownFeaturesModified = true;
622
    }
623
    
624
    @Override
625
    public void commitChanges() throws DataException {
626
        this.ignoreChanges = true;
627
        this.store.commitChanges();
628
        this.ignoreChanges = false;
629
        
630
    }
631

    
632
    @Override
633
    public FeatureStore getFeatureStore() {
634
        return store;
635
    }
636

    
637
}