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

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.EditableFeatureType;
36
import org.gvsig.fmap.dal.feature.Feature;
37
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
38
import org.gvsig.fmap.dal.feature.FeatureIndexes;
39
import org.gvsig.fmap.dal.feature.FeatureQuery;
40
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
41
import org.gvsig.fmap.dal.feature.FeatureQueryOrder.FeatureQueryOrderMember;
42
import org.gvsig.fmap.dal.feature.FeatureSet;
43
import org.gvsig.fmap.dal.feature.FeatureStore;
44
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
45
import org.gvsig.fmap.dal.feature.FeatureType;
46
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
47
import org.gvsig.fmap.dal.feature.exception.FeatureSetInitializeException;
48
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureStore;
49
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureStoreTransforms;
50
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureType;
51
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
52
import org.gvsig.tools.dispose.DisposableIterator;
53
import org.gvsig.tools.dispose.DisposeUtils;
54
import org.gvsig.tools.evaluator.Evaluator;
55
import org.gvsig.tools.observer.Observable;
56
import org.gvsig.tools.observer.Observer;
57

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

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

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

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

    
145
    private void fixQueryForProvider(FeatureQuery theQueryForProvider,
146
        DefaultFeatureStoreTransforms transformsToUse) throws DataException {
147
        theQueryForProvider.clearAttributeNames();
148
        FeatureType ftype =
149
            transformsToUse.getSourceFeatureTypeFrom(this.defaultFeatureType);
150
        theQueryForProvider.setFeatureTypeId(ftype.getId());
151
        this.defatulFeatureTypeForProvider = ftype;
152

    
153
        if (transformsToUse.isTransformsOriginalValues()) {
154
            theQueryForProvider.clearFilter();
155
            FeatureQueryOrder fqo = theQueryForProvider.getOrder();
156
            if (fqo != null) {
157
                fqo.clear();
158
            }
159
            return;
160

    
161
        }
162

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

    
173
            if (!canUseFilter) {
174
                theQueryForProvider.clearFilter();
175
            }
176

    
177
        }
178

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

    
200
            if (!canUseOrder) {
201
                theQueryForProvider.getOrder().clear();
202
            }
203
        }
204

    
205
    }
206

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

    
225
    public FeatureType getDefaultFeatureType() {
226
        return this.defaultFeatureType;
227
    }
228

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
431
    private class LimitIterator implements DisposableIterator {
432

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
544
    private int getIteratorMode() {
545

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

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

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

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

    
591
    }
592

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

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

    
613
    public void update(EditableFeature feature) throws DataException {
614
        this.featureToIgnoreNotification = feature;
615
        this.store.update(feature);
616
        this.featureToIgnoreNotification = null;
617
        this.ownFeaturesModified = true;
618
    }
619
    
620
    public void commitChanges() throws DataException {
621
        this.ignoreChanges = true;
622
        this.store.commitChanges();
623
        this.ignoreChanges = false;
624
        
625
    }
626

    
627
    public FeatureStore getFeatureStore() {
628
        return store;
629
    }
630

    
631
}