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

History | View | Annotate | Download (20 KB)

1 40559 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3 40435 jjdelcerro
 *
4 40559 jjdelcerro
 * Copyright (C) 2007-2013 gvSIG Association.
5 40435 jjdelcerro
 *
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 40559 jjdelcerro
 * as published by the Free Software Foundation; either version 3
9 40435 jjdelcerro
 * 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 40559 jjdelcerro
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23 40435 jjdelcerro
 */
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.Feature;
35
import org.gvsig.fmap.dal.feature.FeatureIndexes;
36
import org.gvsig.fmap.dal.feature.FeatureQuery;
37
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
38 43026 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureQueryOrder.FeatureQueryOrderMember;
39 40435 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureSet;
40
import org.gvsig.fmap.dal.feature.FeatureStore;
41
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
42
import org.gvsig.fmap.dal.feature.FeatureType;
43
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
44
import org.gvsig.fmap.dal.feature.exception.FeatureSetInitializeException;
45
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureStore;
46
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureStoreTransforms;
47
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
48
import org.gvsig.tools.dispose.DisposableIterator;
49 44113 jjdelcerro
import org.gvsig.tools.dispose.DisposeUtils;
50 40435 jjdelcerro
import org.gvsig.tools.evaluator.Evaluator;
51
import org.gvsig.tools.observer.Observable;
52
import org.gvsig.tools.observer.Observer;
53
54 43089 jjdelcerro
public class DefaultFeatureSet extends AbstractFeatureSet implements
55 40435 jjdelcerro
    FeatureSet, Observer {
56
57 44113 jjdelcerro
    protected static final int NO_CHECKED = -1;
58
    protected static final int DEFAULT = 0;
59
    protected static final int FILTERED = 1;
60
    protected static final int ORDERED = 2;
61
    protected static final int ORDERED_FILTERED = 3;
62
    protected static final int EDITED = 4;
63
    protected static final int EDITED_FILTERED = 5;
64
    protected static final int ORDERD_EDITED = 6;
65
    protected static final int ORDERED_EDITED_FILTER = 7;
66 40435 jjdelcerro
67 44113 jjdelcerro
    protected boolean sourceStoreModified;
68
    protected boolean ownFeaturesModified;
69
    protected DefaultFeatureStore store;
70
    protected List featureTypes;
71
    protected FeatureQuery query;
72
    protected FeatureSetProvider provider;
73
    protected long size;
74
    protected int iteratorMode;
75
    protected List orderedData;
76
    protected Feature featureToIgnoreNotification;
77
    protected DefaultFeatureStoreTransforms transform;
78
    protected FeatureQuery queryForProvider;
79
    protected FeatureType defatulFeatureType;
80
    protected FeatureType defatulFeatureTypeForProvider;
81
    protected boolean ignoreChanges;
82 40435 jjdelcerro
83
    public DefaultFeatureSet(DefaultFeatureStore store, FeatureQuery query)
84
        throws DataException {
85
        this.featureToIgnoreNotification = null;
86
        this.iteratorMode = NO_CHECKED;
87
        this.sourceStoreModified = false;
88
        this.ownFeaturesModified = false;
89
        this.size = -1;
90
        this.orderedData = null;
91
        this.store = store;
92
        if (this.store.isEditing()) {
93
            this.transform = this.store.getFeatureTypeManager().getTransforms();
94
        } else {
95
            this.transform =
96
                (DefaultFeatureStoreTransforms) store.getTransforms();
97
        }
98
        this.query = query;
99
        try {
100
            this.queryForProvider = (FeatureQuery) query.clone();
101
        } catch (CloneNotSupportedException e) {
102
            throw new FeatureSetInitializeException(e);
103
        }
104
105
        this.featureTypes = new ArrayList();
106
        if (this.query.getFeatureTypeId() == null
107
            && this.query.getAttributeNames() == null) {
108
            this.defatulFeatureType = this.store.getDefaultFeatureType();
109
            this.featureTypes.addAll(this.store.getFeatureTypes());
110
        } else {
111
            this.defatulFeatureType = this.store.getFeatureType(this.query);
112
            this.featureTypes.add(this.defatulFeatureType);
113
        }
114
        if (this.transform != null && !this.transform.isEmpty()) {
115
            this.fixQueryForProvider(this.queryForProvider, this.transform);
116
        } else {
117
            this.defatulFeatureTypeForProvider = this.defatulFeatureType;
118
        }
119
120
        FeatureIndexes indexes = store.getIndexes();
121
        if (this.queryForProvider.hasFilter() && indexes != null
122
            && indexes.areValid()) {
123
            this.provider =
124
                (FeatureSetProvider) indexes
125
                    .getFeatureSet(this.queryForProvider.getFilter());
126
        }
127
        if (this.provider == null) {
128
            this.provider =
129
                this.store.getProvider().createSet(this.queryForProvider,
130
                    this.defatulFeatureTypeForProvider);
131
        }
132
        this.store.addObserver(this);
133
    }
134
135
    private void fixQueryForProvider(FeatureQuery theQueryForProvider,
136
        DefaultFeatureStoreTransforms transformsToUse) throws DataException {
137 42975 jjdelcerro
        theQueryForProvider.clearAttributeNames();
138 40435 jjdelcerro
        FeatureType ftype =
139
            transformsToUse.getSourceFeatureTypeFrom(this.defatulFeatureType);
140
        theQueryForProvider.setFeatureTypeId(ftype.getId());
141
        this.defatulFeatureTypeForProvider = ftype;
142
143
        if (transformsToUse.isTransformsOriginalValues()) {
144 42975 jjdelcerro
            theQueryForProvider.clearFilter();
145 40435 jjdelcerro
            FeatureQueryOrder fqo = theQueryForProvider.getOrder();
146
            if (fqo != null) {
147
                fqo.clear();
148
            }
149
            return;
150
151
        }
152
153
        // Filter
154
        Evaluator filter = theQueryForProvider.getFilter();
155
        if (filter != null) {
156 44113 jjdelcerro
            boolean canUseFilter;
157 40435 jjdelcerro
            if (filter.getFieldsInfo() == null) {
158
                canUseFilter = false;
159
            } else {
160
                canUseFilter = areEvaluatorFieldsInAttributes(filter, ftype);
161
            }
162
163
            if (!canUseFilter) {
164 42975 jjdelcerro
                theQueryForProvider.clearFilter();
165 40435 jjdelcerro
            }
166
167
        }
168
169
        // Order
170
        if (theQueryForProvider.hasOrder()) {
171
            boolean canUseOrder = true;
172
            Iterator iter = theQueryForProvider.getOrder().iterator();
173
            FeatureQueryOrderMember item;
174
            while (iter.hasNext()) {
175
                item = (FeatureQueryOrderMember) iter.next();
176
                if (item.hasEvaluator()) {
177
                    if (!areEvaluatorFieldsInAttributes(item.getEvaluator(),
178
                        ftype)) {
179
                        canUseOrder = false;
180
                        break;
181
                    }
182
                } else {
183
                    if (ftype.get(item.getAttributeName()) == null) {
184
                        canUseOrder = false;
185
                        break;
186
                    }
187
                }
188
            }
189
190
            if (!canUseOrder) {
191
                theQueryForProvider.getOrder().clear();
192
            }
193
        }
194
195
    }
196
197
    private boolean areEvaluatorFieldsInAttributes(Evaluator evaluator,
198
        FeatureType fType) {
199
        if (evaluator.getFieldsInfo() == null) {
200
            return false;
201
        }
202
        String[] fieldNames = evaluator.getFieldsInfo().getFieldNames();
203
        if (fieldNames.length == 0) {
204
            return false;
205
        } else {
206 44113 jjdelcerro
            for (String fieldName : fieldNames) {
207
                if (fType.get(fieldName) == null) {
208 40435 jjdelcerro
                    return false;
209
                }
210
            }
211
        }
212
        return true;
213
    }
214
215
    public FeatureType getDefaultFeatureType() {
216
        return this.defatulFeatureType;
217
    }
218
219
    public List getFeatureTypes() {
220
        return Collections.unmodifiableList(this.featureTypes);
221
    }
222
223
    public long getSize() throws DataException {
224
        this.checkSourceStoreModified();
225
        if (size < 0) {
226
            size = calculateSize();
227
        }
228
        return size;
229
    }
230
231
    private long calculateSize() throws DataException {
232 44202 jjdelcerro
        long limit = this.query.getLimit();
233
        long mySize = 0;
234
235 40435 jjdelcerro
        int mode = this.getIteratorMode();
236 44202 jjdelcerro
        switch (mode) {
237
        case DEFAULT:
238
        case ORDERED:
239 40435 jjdelcerro
            if (this.provider.isEmpty()) {
240
                return 0;
241
            }
242 44202 jjdelcerro
            mySize = provider.getSize();
243
            return (limit>0 && mySize>limit)? limit:mySize;
244
245
        case FILTERED:
246
        case ORDERED_FILTERED:
247 40435 jjdelcerro
            DisposableIterator iter = null;
248
            try {
249
                iter = this.fastIterator();
250 43980 omartinez
                while ((limit>0 && (mySize<limit)) || limit==0 ) {
251 40435 jjdelcerro
                    iter.next();
252
                    mySize++;
253
                }
254
            } catch (NoSuchElementException e) {
255 44202 jjdelcerro
256 40435 jjdelcerro
            } finally {
257 44113 jjdelcerro
                DisposeUtils.disposeQuietly(iter);
258 40435 jjdelcerro
            }
259 44202 jjdelcerro
            return mySize;
260
261
        case EDITED:
262
        case EDITED_FILTERED:
263
        case ORDERD_EDITED:
264
        case ORDERED_EDITED_FILTER:
265
            mySize = provider.getSize()
266 43983 jjdelcerro
                + store.getFeatureManager().getDeltaSize();
267
            return (limit>0 && mySize>limit)? limit:mySize;
268 44202 jjdelcerro
269
        default:
270
            throw new IllegalArgumentException();
271 43983 jjdelcerro
        }
272 40435 jjdelcerro
    }
273
274
    public void dispose() {
275
        this.store.deleteObserver(this);
276
        this.provider.dispose();
277
        this.provider = null;
278
279
        this.featureToIgnoreNotification = null;
280
        if (orderedData != null) {
281
            orderedData.clear();
282
        }
283
        this.orderedData = null;
284
        this.store = null;
285
        this.transform = null;
286
        this.query = null;
287
        this.queryForProvider = null;
288
        this.featureTypes = null;
289
        this.defatulFeatureType = null;
290
        this.defatulFeatureTypeForProvider = null;
291
    }
292
293
    public void update(Observable obsevable, Object notification) {
294
        if (sourceStoreModified) {
295
            return;
296
        }
297
298
        String type = ((FeatureStoreNotification) notification).getType();
299
300
        if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_INSERT)
301
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_DELETE)
302
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UPDATE)) {
303
            if (this.featureToIgnoreNotification == ((FeatureStoreNotification) notification)
304
                .getFeature()) {
305
                return;
306
            }
307
            sourceStoreModified = true;
308
            return;
309
        }
310
        if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UPDATE_TYPE)
311
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_REDO)
312
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UNDO)
313
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_REFRESH)
314
            || type
315
                .equalsIgnoreCase(FeatureStoreNotification.COMPLEX_NOTIFICATION)
316
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_CLOSE)
317
            || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_DISPOSE)
318
            || type.equalsIgnoreCase(FeatureStoreNotification.TRANSFORM_CHANGE)) {
319
            sourceStoreModified = true;
320
            return;
321
        }
322 44097 omartinez
        if (type.equalsIgnoreCase(FeatureStoreNotification.RESOURCE_CHANGED)) {
323
            if(!this.ignoreChanges) {
324
                sourceStoreModified = true;
325
                return;
326
            }
327 40435 jjdelcerro
        }
328 44097 omartinez
        if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_CANCELEDITING)) {
329
            if (ownFeaturesModified) {
330
                sourceStoreModified = true;
331
                return;
332
            }
333
        }
334 40435 jjdelcerro
    }
335 43358 jjdelcerro
336 40435 jjdelcerro
    protected void checkSourceStoreModified() {
337
        if (sourceStoreModified) {
338
                        throw new ConcurrentDataModificationException(store == null ? ""
339
                                        : store.getName());
340
        }
341
    }
342
343 43358 jjdelcerro
    @Override
344 40435 jjdelcerro
    public DisposableIterator fastIterator(long index) throws DataException {
345 43358 jjdelcerro
        return fastIterator(index, 0);
346
    }
347
348
    @Override
349
    public DisposableIterator fastIterator(long index, long elements) throws DataException {
350 40435 jjdelcerro
        if (index < 0) {
351
            throw new IndexOutOfBoundsException("The index (" + index
352
                + ") is less than 0");
353
        }
354 43913 jjdelcerro
        DisposableIterator it;
355 40435 jjdelcerro
        int mode = this.getIteratorMode();
356
357
        switch (mode) {
358
        case DEFAULT:
359 43913 jjdelcerro
            it = new FastDefaultIterator(this, index, elements);
360
            break;
361 40435 jjdelcerro
362
        case FILTERED:
363 43913 jjdelcerro
            it = new FastFilteredIterator(this, index);
364
            break;
365 40435 jjdelcerro
366
        case ORDERED:
367
            if (this.orderedData != null) {
368 43913 jjdelcerro
                it = new FastOrderedIterator(this, index);
369 40435 jjdelcerro
            } else {
370 43913 jjdelcerro
                it = new FastOrderedIterator(this, new FastDefaultIterator(this, 0, elements), index);
371 40435 jjdelcerro
            }
372 43913 jjdelcerro
            break;
373
374 40435 jjdelcerro
        case ORDERED_FILTERED:
375
            if (this.orderedData != null) {
376 43913 jjdelcerro
                it = new FastOrderedIterator(this, index);
377 40435 jjdelcerro
            } else {
378 43913 jjdelcerro
                it = new FastOrderedIterator(this, new FastFilteredIterator(
379 40435 jjdelcerro
                    this, 0), index);
380
            }
381 43913 jjdelcerro
            break;
382 40435 jjdelcerro
383
        case EDITED:
384 43913 jjdelcerro
            it = new FastEditedIterator(this, index);
385
            break;
386 40435 jjdelcerro
387
        case EDITED_FILTERED:
388 43913 jjdelcerro
            it = new FastEditedFilteredIterator(this, index);
389
            break;
390 40435 jjdelcerro
391
        case ORDERD_EDITED:
392
            if (this.orderedData != null) {
393 43913 jjdelcerro
                it = new FastOrderedIterator(this, index);
394 40435 jjdelcerro
            } else {
395 43913 jjdelcerro
                it = new FastOrderedIterator(this, new FastEditedIterator(
396 40435 jjdelcerro
                    this, 0), index);
397
            }
398 43913 jjdelcerro
            break;
399 40435 jjdelcerro
400
        case ORDERED_EDITED_FILTER:
401
            if (this.orderedData != null) {
402 43913 jjdelcerro
                it = new FastOrderedIterator(this, index);
403 40435 jjdelcerro
            } else {
404 43913 jjdelcerro
                it = new FastOrderedIterator(this,
405 40435 jjdelcerro
                    new FastEditedFilteredIterator(this, 0), index);
406
            }
407 43913 jjdelcerro
            break;
408
409 40435 jjdelcerro
        default:
410
            throw new IllegalArgumentException();
411
        }
412 43913 jjdelcerro
        if( this.query!=null && this.query.getLimit()>0 ) {
413
            it = new LimitIterator(it,this.query.getLimit());
414
        }
415
        return it;
416 40435 jjdelcerro
    }
417
418 43913 jjdelcerro
    private class LimitIterator implements DisposableIterator {
419 40435 jjdelcerro
420 43913 jjdelcerro
        private final DisposableIterator it;
421
        private final long limit;
422
        private int count;
423
424
        private LimitIterator(DisposableIterator it, long limit) {
425
            this.it = it;
426
            this.limit = limit;
427
            this.count = 0;
428
        }
429
430
        @Override
431
        public void dispose() {
432
            this.it.dispose();
433
        }
434
435
        @Override
436
        public boolean hasNext() {
437
            if( this.count>=this.limit ) {
438
                return false;
439
            }
440
            return this.it.hasNext();
441
        }
442
443
        @Override
444
        public Object next() {
445
            if( this.count>=this.limit ) {
446
                return null;
447
            }
448
            this.count++;
449
            return this.it.next();
450
        }
451
452
        @Override
453
        public void remove() {
454
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
455
        }
456
457
    }
458
459 43358 jjdelcerro
    @Override
460 40435 jjdelcerro
    public DisposableIterator iterator(long index) throws DataException {
461 43358 jjdelcerro
        return iterator(index,0);
462
    }
463
464
    @Override
465
    public DisposableIterator iterator(long index, long elements) throws DataException {
466 40435 jjdelcerro
        if (index < 0) {
467
            throw new IndexOutOfBoundsException("The index (" + index
468
                + ") is less than 0");
469
        }
470 43913 jjdelcerro
        DisposableIterator it;
471 40435 jjdelcerro
        int mode = this.getIteratorMode();
472
473
        switch (mode) {
474
        case DEFAULT:
475 43913 jjdelcerro
            it = new DefaultIterator(this, index, elements);
476
            break;
477 40435 jjdelcerro
478
        case FILTERED:
479 43913 jjdelcerro
            it = new FilteredIterator(this, index);
480
            break;
481 40435 jjdelcerro
482
        case ORDERED:
483
            if (orderedData != null) {
484 43913 jjdelcerro
                it = new OrderedIterator(this, index);
485 40435 jjdelcerro
486
            } else {
487 43913 jjdelcerro
                it = new OrderedIterator(this, new DefaultIterator(this, 0, elements),index);
488 40435 jjdelcerro
            }
489 43913 jjdelcerro
            break;
490 40435 jjdelcerro
491
        case ORDERED_FILTERED:
492 43913 jjdelcerro
            it = new OrderedIterator(this, new FilteredIterator(this, 0),
493 40435 jjdelcerro
                index);
494 43913 jjdelcerro
            break;
495 40435 jjdelcerro
496
        case EDITED:
497 43913 jjdelcerro
            it = new EditedIterator(this, index);
498
            break;
499 40435 jjdelcerro
500
        case EDITED_FILTERED:
501 43913 jjdelcerro
            it = new EditedFilteredIterator(this, index);
502
            break;
503 40435 jjdelcerro
504
        case ORDERD_EDITED:
505 43913 jjdelcerro
            it = new OrderedIterator(this, new EditedIterator(this, 0), index);
506
            break;
507 40435 jjdelcerro
508
        case ORDERED_EDITED_FILTER:
509 43913 jjdelcerro
            it = new OrderedIterator(this,
510 40435 jjdelcerro
                new EditedFilteredIterator(this, 0), index);
511 43913 jjdelcerro
            break;
512 40435 jjdelcerro
513
        default:
514
            throw new IllegalArgumentException();
515
        }
516
517 43913 jjdelcerro
        if( this.query!=null && this.query.getLimit()>0 ) {
518
            it = new LimitIterator(it,this.query.getLimit());
519
        }
520
        return it;
521 40435 jjdelcerro
    }
522
523
    private boolean providerCanOrder() {
524
        return this.provider.canOrder();
525
    }
526
527
    private boolean providerCanFilter() {
528
        return this.provider.canFilter();
529
    }
530
531
    private int getIteratorMode() {
532
533
        if (this.iteratorMode != NO_CHECKED) {
534
            return this.iteratorMode;
535
        }
536
537
        // TODO Tener en cuenta las transformaciones ???
538
539 43981 omartinez
        if (store.isEditing() && (store.getFeatureTypeManager().hasChanges() || store.getFeatureManager().hasChanges())) {
540 40435 jjdelcerro
            if (this.query.hasOrder()) { // En edicion siempre ordeno yo.
541
                if (this.query.hasFilter()) {
542
                    return ORDERED_EDITED_FILTER;
543
                } else {
544
                    return ORDERD_EDITED;
545
                }
546
            } else {
547
                if (this.query.hasFilter()) {
548
                    return EDITED_FILTERED;
549
                } else {
550
                    return EDITED;
551
                }
552
            }
553
        } else {
554
            boolean useMyFilter = this.query.hasFilter();
555
            boolean useMyOrder = this.query.hasOrder();
556
            if (this.providerCanOrder() && this.transform.isEmpty()) {
557
                useMyOrder = false;
558
            }
559
            if (this.providerCanFilter() && this.transform.isEmpty()) {
560
                useMyFilter = false;
561
            }
562
563
            if (useMyOrder) {
564
                if (useMyFilter) {
565 44191 jjdelcerro
                    return ORDERED_FILTERED;
566 40435 jjdelcerro
                } else {
567 44191 jjdelcerro
                    return ORDERED;
568 40435 jjdelcerro
                }
569
            } else {
570
                if (useMyFilter) {
571 44191 jjdelcerro
                    return FILTERED;
572 40435 jjdelcerro
                } else {
573 44191 jjdelcerro
                    return DEFAULT;
574 40435 jjdelcerro
                }
575
            }
576
        }
577
578
    }
579
580
    public void delete(Feature feature) throws DataException {
581
        this.featureToIgnoreNotification = feature;
582
        this.store.delete(feature);
583
        if (this.size > 0) {
584
            this.size--;
585
        }
586
        this.featureToIgnoreNotification = null;
587
        this.ownFeaturesModified = true;
588
    }
589
590
    public void insert(EditableFeature feature) throws DataException {
591
        this.featureToIgnoreNotification = feature;
592
        this.store.insert(feature);
593
        if (this.size >= 0) {
594
            this.size++;
595
        }
596
        this.featureToIgnoreNotification = null;
597
        this.ownFeaturesModified = true;
598
    }
599
600
    public void update(EditableFeature feature) throws DataException {
601
        this.featureToIgnoreNotification = feature;
602
        this.store.update(feature);
603
        this.featureToIgnoreNotification = null;
604
        this.ownFeaturesModified = true;
605
    }
606 44097 omartinez
607
    public void commitChanges() throws DataException {
608
        this.ignoreChanges = true;
609
        this.store.commitChanges();
610
        this.ignoreChanges = false;
611
612
    }
613 40435 jjdelcerro
614
    public FeatureStore getFeatureStore() {
615
        return store;
616
    }
617 43358 jjdelcerro
618 40435 jjdelcerro
}