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 / DefaultFeatureStore.java @ 46390

History | View | Annotate | Download (139 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;
25

    
26
import java.util.ArrayList;
27
import java.util.Collection;
28
import java.util.Collections;
29
import java.util.HashMap;
30
import java.util.HashSet;
31
import java.util.Iterator;
32
import java.util.List;
33
import java.util.Map;
34
import java.util.Map.Entry;
35
import java.util.Objects;
36
import java.util.Set;
37
import java.util.UUID;
38
import javax.json.JsonObject;
39
import org.apache.commons.io.FilenameUtils;
40
import org.apache.commons.io.IOUtils;
41
import org.apache.commons.lang3.StringUtils;
42
import org.apache.commons.lang3.mutable.MutableObject;
43
import org.cresques.cts.IProjection;
44
import org.gvsig.expressionevaluator.Expression;
45
import org.gvsig.expressionevaluator.ExpressionBuilder;
46
import org.gvsig.expressionevaluator.ExpressionUtils;
47
import org.gvsig.expressionevaluator.GeometryExpressionUtils;
48
import org.gvsig.fmap.dal.BaseStoresRepository;
49
import org.gvsig.fmap.dal.DALLocator;
50
import org.gvsig.fmap.dal.DataManager;
51
import static org.gvsig.fmap.dal.DataManager.DAL_STORE_ENVELOPE;
52
import static org.gvsig.fmap.dal.DataManager.DAL_USE_LARGE_SELECTION;
53
import org.gvsig.fmap.dal.DataQuery;
54
import org.gvsig.fmap.dal.DataServerExplorer;
55
import org.gvsig.fmap.dal.DataSet;
56
import org.gvsig.fmap.dal.DataStore;
57
import org.gvsig.fmap.dal.DataStoreNotification;
58
import org.gvsig.fmap.dal.DataStoreParameters;
59
import org.gvsig.fmap.dal.DataStoreProviderFactory;
60
import org.gvsig.fmap.dal.DataTransaction;
61
import org.gvsig.fmap.dal.DataTypes;
62
import org.gvsig.fmap.dal.StoresRepository;
63
import org.gvsig.fmap.dal.SupportTransactions;
64
import org.gvsig.fmap.dal.exception.CloneException;
65
import org.gvsig.fmap.dal.exception.CloseException;
66
import org.gvsig.fmap.dal.exception.CreateException;
67
import org.gvsig.fmap.dal.exception.DataException;
68
import org.gvsig.fmap.dal.exception.DataRuntimeException;
69
import org.gvsig.fmap.dal.exception.InitializeException;
70
import org.gvsig.fmap.dal.exception.OpenException;
71
import org.gvsig.fmap.dal.exception.ReadException;
72
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
73
import org.gvsig.fmap.dal.exception.WriteException;
74
import org.gvsig.fmap.dal.feature.EditableFeature;
75
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
76
import org.gvsig.fmap.dal.feature.EditableFeatureType;
77
import org.gvsig.fmap.dal.feature.Feature;
78
import static org.gvsig.fmap.dal.feature.Feature.CHECK_BASIC;
79
import static org.gvsig.fmap.dal.feature.Feature.CHECK_REQUIREDS;
80
import static org.gvsig.fmap.dal.feature.Feature.CHECK_RULES_AT_EDITING;
81
import static org.gvsig.fmap.dal.feature.Feature.CHECK_RULES_AT_FINISH;
82
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
83
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
84
import org.gvsig.fmap.dal.feature.FeatureCache;
85
import org.gvsig.fmap.dal.feature.FeatureIndex;
86
import org.gvsig.fmap.dal.feature.FeatureIndexes;
87
import org.gvsig.fmap.dal.feature.FeatureLocks;
88
import org.gvsig.fmap.dal.feature.FeatureQuery;
89
import org.gvsig.fmap.dal.feature.FeatureReference;
90
import org.gvsig.fmap.dal.feature.FeatureReferenceSelection;
91
import org.gvsig.fmap.dal.feature.FeatureSelection;
92
import org.gvsig.fmap.dal.feature.FeatureSet;
93
import org.gvsig.fmap.dal.feature.FeatureSet.DisposableFeatureSetIterable;
94
import org.gvsig.fmap.dal.feature.FeatureStore;
95
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
96
import org.gvsig.fmap.dal.feature.FeatureStoreProviderFactory;
97
import org.gvsig.fmap.dal.feature.FeatureStoreTimeSupport;
98
import org.gvsig.fmap.dal.feature.FeatureStoreTransform;
99
import org.gvsig.fmap.dal.feature.FeatureStoreTransforms;
100
import org.gvsig.fmap.dal.feature.FeatureType;
101
import org.gvsig.fmap.dal.feature.FeatureType.FeatureTypeChanged;
102
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
103
import org.gvsig.fmap.dal.feature.exception.AlreadyEditingException;
104
import org.gvsig.fmap.dal.feature.exception.CreateFeatureException;
105
import org.gvsig.fmap.dal.feature.exception.DataExportException;
106
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
107
import org.gvsig.fmap.dal.feature.exception.FinishEditingException;
108
import org.gvsig.fmap.dal.feature.exception.GetFeatureTypeException;
109
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureException;
110
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureTypeException;
111
import org.gvsig.fmap.dal.feature.exception.NeedEditingModeException;
112
import org.gvsig.fmap.dal.feature.exception.NoNewFeatureInsertException;
113
import org.gvsig.fmap.dal.feature.exception.NullFeatureTypeException;
114
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
115
import org.gvsig.fmap.dal.feature.exception.PersistenceCantFindFeatureTypeException;
116
import org.gvsig.fmap.dal.feature.exception.PersistenceStoreAlreadyLoadedException;
117
import org.gvsig.fmap.dal.feature.exception.SelectionNotAllowedException;
118
import org.gvsig.fmap.dal.feature.exception.StoreCancelEditingException;
119
import org.gvsig.fmap.dal.feature.exception.StoreDeleteEditableFeatureException;
120
import org.gvsig.fmap.dal.feature.exception.StoreDeleteFeatureException;
121
import org.gvsig.fmap.dal.feature.exception.StoreEditException;
122
import org.gvsig.fmap.dal.feature.exception.StoreInsertFeatureException;
123
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureException;
124
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureTypeException;
125
import org.gvsig.fmap.dal.feature.exception.ValidateFeaturesException;
126
import org.gvsig.fmap.dal.feature.exception.WriteNotAllowedException;
127
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
128
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureManager;
129
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureTypeManager;
130
import org.gvsig.fmap.dal.feature.impl.editing.memory.SpatialManager;
131
import org.gvsig.fmap.dal.feature.impl.featurereference.FeatureReferenceFactory;
132
import org.gvsig.fmap.dal.feature.impl.featurereference.FeatureReferenceIteratorToFeatureIterator;
133
import org.gvsig.fmap.dal.feature.impl.featureset.DefaultFeatureSet;
134
import org.gvsig.fmap.dal.feature.impl.undo.DefaultFeatureCommandsStack;
135
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
136
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
137
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
138
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
139
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
140
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
141
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
142
import org.gvsig.fmap.dal.feature.spi.cache.FeatureCacheProvider;
143
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProviderServices;
144
import org.gvsig.fmap.dal.impl.DefaultDataManager;
145
import org.gvsig.fmap.dal.resource.Resource;
146
import org.gvsig.fmap.dal.spi.AbstractDataStore;
147
import org.gvsig.fmap.dal.spi.DataStoreInitializer2;
148
import org.gvsig.fmap.dal.spi.DataStoreProvider;
149
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
150
import org.gvsig.fmap.dal.spi.DataTransactionServices;
151
import org.gvsig.fmap.geom.Geometry;
152
import org.gvsig.fmap.geom.GeometryUtils;
153
import org.gvsig.fmap.geom.SpatialIndex;
154
import org.gvsig.fmap.geom.primitive.Envelope;
155
import org.gvsig.metadata.MetadataLocator;
156
import org.gvsig.metadata.MetadataManager;
157
import org.gvsig.metadata.exceptions.MetadataException;
158
import org.gvsig.timesupport.Interval;
159
import org.gvsig.tools.ToolsLocator;
160
import org.gvsig.tools.dispose.DisposableIterator;
161
import org.gvsig.tools.dispose.DisposeUtils;
162
import org.gvsig.tools.dynobject.DelegatedDynObject;
163
import org.gvsig.tools.dynobject.DynClass;
164
import org.gvsig.tools.dynobject.DynObject;
165
import org.gvsig.tools.dynobject.DynObjectManager;
166
import org.gvsig.tools.dynobject.DynObject_v2;
167
import org.gvsig.tools.dynobject.DynStruct;
168
import org.gvsig.tools.dynobject.Tags;
169
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
170
import org.gvsig.tools.dynobject.exception.DynMethodException;
171
import org.gvsig.tools.exception.BaseException;
172
import org.gvsig.tools.exception.NotYetImplemented;
173
import org.gvsig.tools.identitymanagement.SimpleIdentityManager;
174
import org.gvsig.tools.observer.BaseNotification;
175
import org.gvsig.tools.observer.Observable;
176
import org.gvsig.tools.observer.Observer;
177
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
178
import org.gvsig.tools.persistence.PersistenceManager;
179
import org.gvsig.tools.persistence.Persistent;
180
import org.gvsig.tools.persistence.PersistentState;
181
import org.gvsig.tools.persistence.exception.PersistenceException;
182
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
183
import org.gvsig.tools.undo.RedoException;
184
import org.gvsig.tools.undo.UndoException;
185
import org.gvsig.tools.undo.command.Command;
186
import org.gvsig.tools.util.CachedValue;
187
import org.gvsig.tools.util.ChainedIterator;
188
import org.gvsig.tools.util.GetItemWithSizeIsEmptyAndIterator64;
189
import org.gvsig.tools.util.HasAFile;
190
import org.gvsig.tools.util.PropertiesSupportHelper;
191
import org.gvsig.tools.util.UnmodifiableBasicMap;
192
import org.gvsig.tools.visitor.VisitCanceledException;
193
import org.gvsig.tools.visitor.Visitor;
194

    
195
@SuppressWarnings("UseSpecificCatch")
196
public class DefaultFeatureStore extends AbstractDataStore implements
197
        DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore,
198
        SupportTransactions, Observer {
199

    
200
    public static long sample_feature_cache_timeout_ms = 15000;
201
    
202
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
203

    
204
    private DataStoreParameters parameters = null;
205
    private FeatureSelection selection;
206
    private FeatureLocks locks;
207

    
208
    private DelegateWeakReferencingObservable delegateObservable
209
            = new DelegateWeakReferencingObservable(this);
210

    
211
    private FeatureCommandsStack commands;
212

    
213
    /*
214
    TODO: Sustituir estos tres manager por un EditingManager
215
     */
216
    private FeatureTypeManager featureTypeManager;
217
    private FeatureManager featureManager;
218
    private SpatialManager spatialManager;
219

    
220
    private FeatureType defaultFeatureType = null;
221
    private List<FeatureType> featureTypes = new ArrayList<>();
222

    
223
    private int mode = MODE_QUERY;
224
    private long versionOfUpdate = 0;
225
    private boolean hasStrongChanges = true;
226

    
227
    private DefaultDataManager dataManager = null;
228

    
229
    private FeatureStoreProvider provider = null;
230

    
231
    private DefaultFeatureIndexes indexes;
232

    
233
    private DefaultFeatureStoreTransforms transforms;
234

    
235
    /*friend*/ DelegatedDynObject metadata;
236

    
237
    private Set metadataChildren;
238

    
239
    private Long featureCount = null;
240

    
241
    private long temporalOid = 0;
242

    
243
    private FeatureCacheProvider cache;
244

    
245
    private final StateInformation state;
246

    
247
    private FeatureStoreTimeSupport timeSupport;
248

    
249
    private PropertiesSupportHelper propertiesSupportHelper;
250
    private DataTransaction transaction;
251

    
252
    private String editingSessionCode;
253
    
254
    private CachedValue<Feature> sampleFeatureCache;
255
    
256
    private final Observer transactionObserver;
257

    
258
    private class StateInformation extends HashMap<Object, Object> {
259

    
260
        private static final long serialVersionUID = 4109026189635185666L;
261

    
262
        private boolean broken;
263
        private Throwable breakingsCause;
264

    
265
        @SuppressWarnings("OverridableMethodCallInConstructor")
266
        public StateInformation() {
267
            this.clear();
268
        }
269

    
270
        @Override
271
        public void clear() {
272
            this.broken = false;
273
            this.breakingsCause = null;
274
            super.clear();
275
        }
276

    
277
        public boolean isBroken() {
278
            return this.broken;
279
        }
280

    
281
        public void broken() {
282
            this.broken = true;
283
        }
284

    
285
        public Throwable getBreakingsCause() {
286
            return this.breakingsCause;
287
        }
288

    
289
        public void setBreakingsCause(Throwable cause) {
290
            if (this.breakingsCause == null) {
291
                this.breakingsCause = cause;
292
            }
293
            this.broken = true;
294
        }
295
    }
296

    
297
    /*
298
     * TODO:
299
     *
300
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
301
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
302
     * featureType al que se le han cambiado las reglas de validacion cuando
303
     * hasStrongChanges=false.
304
     */
305
    public DefaultFeatureStore() {
306
        this.state = new StateInformation();
307
        this.sampleFeatureCache = null;
308
        this.transactionObserver = new Observer() {
309
            @Override
310
            public void update(Observable o, Object o1) {
311
                if( o1 instanceof BaseNotification && (
312
                        ((BaseNotification)o1).isOfType("ROLLBACK") ||
313
                        ((BaseNotification)o1).isOfType("COMMIT")
314
                        ) ) {
315
                    featureCount = null;
316
                }
317
            }
318
        };
319
    }
320

    
321
    @Override
322
    protected DataManager getDataManager() {
323
        return this.dataManager;
324
    }
325

    
326
    @Override
327
    public void intialize(DataManager dataManager,
328
            DataStoreParameters parameters) throws InitializeException {
329

    
330
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
331

    
332
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
333
                FeatureStore.METADATA_DEFINITION_NAME,
334
                MetadataManager.METADATA_NAMESPACE
335
        );
336

    
337
        this.dataManager = (DefaultDataManager) dataManager;
338

    
339
        this.parameters = parameters;
340
        this.transforms = new DefaultFeatureStoreTransforms(this);
341
        try {
342
            indexes = new DefaultFeatureIndexes(this);
343
        } catch (DataException e) {
344
            throw new InitializeException(e);
345
        }
346

    
347
    }
348

    
349
    @Override
350
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
351
        this.provider = (FeatureStoreProvider) provider;
352
        this.delegate((DynObject) provider);
353
        this.metadataChildren = new HashSet();
354
        this.metadataChildren.add(provider);
355
        if (!this.ignoreDALResource) {
356
            loadDALFile();
357

    
358
            // Habria que crear un metodo en el proveedor para que de prioidad
359
            // a los parametros frente a lo que se a leido en el fichero dal
360
            // DataStoreProvider arreglalo segun los parametros del usuario
361
            // fixFeatureTypeFromParameters
362
            this.provider.fixFeatureTypeFromParameters();
363
            try {
364
                if (defaultFeatureType != null) {
365
                    FeatureAttributeDescriptor attrGeom = defaultFeatureType.getDefaultGeometryAttribute();
366
                    if (attrGeom != null) {
367
                        DefaultFeatureAttributeDescriptor gattr = (DefaultFeatureAttributeDescriptor) attrGeom;
368
                        IProjection srs = (IProjection) this.getDynValue(METADATA_CRS);
369
                        if (srs != null && srs != gattr.getSRS()) {
370
                            gattr.setSRSForced(srs);
371
                        }
372
                    }
373
                }
374
            } catch (Throwable th) {
375
                LOGGER.warn("Can't patch DAL file", th);
376
            }
377
        }
378
    }
379

    
380
    @Override
381
    public DataStoreParameters getParameters() {
382
        if (this.parameters == null) {
383
            LOGGER.warn("Store parametes are null");
384
        }
385
        return parameters;
386
    }
387

    
388
    @Override
389
    public int getMode() {
390
        return this.mode;
391
    }
392

    
393
    @Override
394
    public DataManager getManager() {
395
        return this.dataManager;
396
    }
397

    
398
    @Override
399
    public UnmodifiableBasicMap<String, DataStore> getChildren() {
400
        UnmodifiableBasicMap<String, DataStore> children = this.provider.getChildren();
401
        if (children == null) {
402
            return UnmodifiableBasicMap.EMPTY_UNMODIFIABLEBASICMAP;
403
        }
404
        return children;
405
    }
406

    
407
    @Override
408
    public FeatureStoreProvider getProvider() {
409
        return this.provider;
410
    }
411

    
412
    public FeatureManager getFeatureManager() {
413
        return this.featureManager;
414
    }
415

    
416
    @Override
417
    public void setFeatureTypes(List types, FeatureType defaultType) {
418
        this.featureTypes = types;
419
        this.defaultFeatureType = defaultType;
420
    }
421

    
422
    public void open() throws OpenException {
423
        if (this.mode != MODE_QUERY) {
424
            // TODO: Se puede hacer un open estando en edicion ?
425
            try {
426
                throw new IllegalStateException();
427
            } catch (Exception ex) {
428
                LOGGER.warn("Opening a store in editing/append mode (" + this.getFullName() + ").", ex);
429
            }
430
        }
431
        if (this.notifyChange(DataStoreNotification.BEFORE_OPEN).isCanceled()) {
432
            return;
433
        }
434
        this.provider.open();
435
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
436
    }
437

    
438
    @Override
439
    public void refresh() throws OpenException, InitializeException {
440
        if (this.mode != MODE_QUERY) {
441
            throw new IllegalStateException();
442
        }
443
        if (this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH).isCanceled()) {
444
            return;
445
        }
446
        if (state.isBroken()) {
447
            this.load(state);
448
        } else {
449
            this.featureCount = null;
450
            this.provider.refresh();
451
        }
452
        this.resourcesStorage = null;
453
        loadDALFile();
454
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
455
    }
456

    
457
    public void close() throws CloseException {
458
        if (this.mode != MODE_QUERY) {
459
            // TODO: Se puede hacer un close estando en edicion ?
460
            try {
461
                throw new IllegalStateException();
462
            } catch (Exception ex) {
463
                LOGGER.warn("Clossing a store in editing/append mode (" + this.getFullName() + ").", ex);
464
            }
465
        }
466
        if (this.notifyChange(DataStoreNotification.BEFORE_CLOSE).isCanceled()) {
467
            return;
468
        }
469
        this.featureCount = null;
470
        this.provider.close();
471
        this.notifyChange(DataStoreNotification.AFTER_CLOSE);
472
    }
473

    
474
    @Override
475
    protected void doDispose() throws BaseException {
476
        if (this.mode != MODE_QUERY) {
477
            // TODO: Se puede hacer un dispose estando en edicion ?
478
            try {
479
                throw new IllegalStateException();
480
            } catch (Exception ex) {
481
                LOGGER.warn("Dispossing a store in editing/append mode (" + this.getFullName() + ").", ex);
482
            }
483
        }
484
        if (this.notifyChange(DataStoreNotification.BEFORE_DISPOSE).isCanceled()) {
485
            return;
486
        }
487
        this.disposeIndexes();
488
        if (this.provider != null) {
489
            this.provider.dispose();
490
        }
491
        if (this.selection != null) {
492
            this.selection.dispose();
493
            this.selection = null;
494
        }
495
        this.commands = null;
496
        this.featureCount = null;
497
        if (this.locks != null) {
498
            // this.locks.dispose();
499
            this.locks = null;
500
        }
501

    
502
        if (this.featureTypeManager != null) {
503
            this.featureTypeManager.dispose();
504
            this.featureTypeManager = null;
505
        }
506

    
507
        this.featureManager = null;
508
        this.spatialManager = null;
509

    
510
        this.parameters = null;
511
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
512
        if (delegateObservable != null) {
513
            this.delegateObservable.deleteObservers();
514
            this.delegateObservable = null;
515
        }
516
        DisposeUtils.disposeQuietly(this.resourcesStorage);
517
        if( this.transaction!=null ) {
518
            this.transaction.deleteObserver(transactionObserver);
519
            this.transaction = null;
520
        }
521
    }
522

    
523
    @Override
524
    public boolean allowWrite() {
525
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
526
        if (!identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION, this.getParameters(), this.getName())) {
527
            return false;
528
        }
529
        return this.provider.allowWrite();
530
    }
531

    
532
    @Override
533
    public boolean canWriteGeometry(int geometryType) throws DataException {
534
        return this.provider.canWriteGeometry(geometryType, 0);
535
    }
536

    
537
    @Override
538
    public DataServerExplorer getExplorer() throws ReadException,
539
            ValidateDataParametersException {
540
        if (this.state.isBroken()) {
541
            try {
542
                return this.provider.getExplorer();
543
            } catch (Throwable th) {
544
                return null;
545
            }
546
        } else {
547
            return this.provider.getExplorer();
548
        }
549
    }
550

    
551
    /*
552
     * public Metadata getMetadata() throws MetadataNotFoundException {
553
     * // TODO:
554
     * // Si el provider devuelbe null habria que ver de construir aqui
555
     * // los metadatos basicos, como el Envelope y el SRS.
556
     *
557
     * // TODO: Estando en edicion el Envelope deberia de
558
     * // actualizarse usando el spatialManager
559
     * return this.provider.getMetadata();
560
     * }
561
     */
562
    @Override
563
    public Envelope getEnvelope() throws DataException {
564
        if (this.mode == MODE_FULLEDIT) {
565
            // Just in case another thread tries to write in the store
566
            synchronized (this) {
567
                return this.spatialManager.getEnvelope();
568
            }
569
        }
570
        try {
571
            FeatureType featureType = this.getDefaultFeatureTypeQuietly();
572
            if( featureType!=null ) {
573
                Tags tags = featureType.getTags();
574
                if( tags.has(DAL_STORE_ENVELOPE) ) {
575
                    String geom_s = tags.getString(DAL_STORE_ENVELOPE,null);
576
                    if( StringUtils.isNotBlank(geom_s) ) {
577
                        Geometry geom = GeometryUtils.createFrom(geom_s);
578
                        if( geom!=null ) {
579
                            return geom.getEnvelope();
580
                        }
581
                    }
582
                }
583
            }
584
        } catch(Throwable th) {
585
            LOGGER.debug("Can't retrieve envelope from featrure type tag '"+DAL_STORE_ENVELOPE+"'.", th);
586
        }
587
        
588
        if (hasDynValue(DataStore.METADATA_ENVELOPE)) {
589
            return (Envelope) getDynValue(DataStore.METADATA_ENVELOPE);
590
        }
591
        Envelope envelope = this.provider.getEnvelope();
592
        if (envelope != null) {
593
            return envelope;
594
        }
595
        FeatureAttributeDescriptor attrdesc = this.getDefaultFeatureType().getDefaultGeometryAttribute();
596
        if (attrdesc == null || !attrdesc.isComputed()) {
597
            return null;
598
        }
599
        final int index = attrdesc.getIndex();
600
        final MutableObject<Envelope> envelopeValue = new MutableObject<>();
601
        try {
602
            this.accept((Object obj) -> {
603
                Feature f = (Feature) obj;
604
                Geometry g = (Geometry) f.get(index);
605
                if (g == null) {
606
                    return;
607
                }
608
                if (envelopeValue.getValue() == null) {
609
                    envelopeValue.setValue(g.getEnvelope());
610
                } else {
611
                    envelopeValue.getValue().add(g);
612
                }
613
            });
614
        } catch (Throwable th) {
615
            LOGGER.warn("Can't calculate envelope", th);
616
            return null;
617
        }
618
        return envelopeValue.getValue();
619
    }
620

    
621
    /**
622
     * @throws org.gvsig.fmap.dal.exception.DataException
623
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
624
     */
625
    @Override
626
    public IProjection getSRSDefaultGeometry() throws DataException {
627
        return this.getDefaultFeatureType().getDefaultSRS();
628
    }
629

    
630
    @Override
631
    public FeatureSelection createDefaultFeatureSelection()
632
            throws DataException {
633
        return new DefaultFeatureSelection(this);
634
    }
635

    
636
    @Override
637
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
638
            throws DataException {
639
        if (type.hasOID()) {
640
            return new DefaultFeatureProvider(type,
641
                    this.provider.createNewOID());
642
        }
643
        return new DefaultFeatureProvider(type);
644
    }
645

    
646
    @Override
647
    public void saveToState(PersistentState state) throws PersistenceException {
648
        /*if (this.mode != FeatureStore.MODE_QUERY) {
649
            throw new PersistenceException(new IllegalStateException(
650
                this.getName()));
651
        }*/
652
        state.set("dataStoreName", this.getName());
653
        state.set("parameters", this.parameters);
654
        state.set("selection", this.selection);
655
        state.set("transforms", this.transforms);
656
        // TODO locks persistence
657
        // state.set("locks", this.locks);
658
        // TODO indexes persistence
659
        // state.set("indexes", this.indexes);
660
        Map evaluatedAttr = new HashMap(1);
661
        Iterator iterType = featureTypes.iterator();
662
        Iterator iterAttr;
663
        FeatureType type;
664
        DefaultFeatureAttributeDescriptor attr;
665
        List attrs;
666
        while (iterType.hasNext()) {
667
            type = (FeatureType) iterType.next();
668
            attrs = new ArrayList();
669
            iterAttr = type.iterator();
670
            while (iterAttr.hasNext()) {
671
                attr = (DefaultFeatureAttributeDescriptor) iterAttr.next();
672
                if ((attr.getEvaluator() != null)
673
                        && (attr.getEvaluator() instanceof Persistent)) {
674
                    attrs.add(attr);
675
                }
676
            }
677
            if (!attrs.isEmpty()) {
678
                evaluatedAttr.put(type.getId(), attrs);
679
            }
680

    
681
        }
682

    
683
        if (evaluatedAttr.isEmpty()) {
684
            evaluatedAttr = null;
685
        }
686

    
687
        state.set("evaluatedAttributes", evaluatedAttr);
688
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
689

    
690
    }
691

    
692
    @Override
693
    public void loadFromState(final PersistentState persistentState)
694
            throws PersistenceException {
695
        if (this.provider != null) {
696
            throw new PersistenceStoreAlreadyLoadedException(this.getName());
697
        }
698
        if (this.getManager() == null) {
699
            this.dataManager = (DefaultDataManager) DALLocator.getDataManager();
700
        }
701
        state.clear();
702
        try {
703
            state.put("parameters", persistentState.get("parameters"));
704
        } catch (Throwable th) {
705
            state.setBreakingsCause(th);
706
        }
707
        try {
708
            state.put("selection", persistentState.get("selection"));
709
        } catch (Throwable th) {
710
            state.setBreakingsCause(th);
711
        }
712
        try {
713
            state.put("transforms", persistentState.get("transforms"));
714
        } catch (Throwable th) {
715
            state.setBreakingsCause(th);
716
        }
717
        try {
718
            state.put("evaluatedAttributes", persistentState.get("evaluatedAttributes"));
719
        } catch (Throwable th) {
720
            state.setBreakingsCause(th);
721
        }
722
        try {
723
            state.put("defaultFeatureTypeId", persistentState.getString("defaultFeatureTypeId"));
724
        } catch (Throwable th) {
725
            state.setBreakingsCause(th);
726
        }
727
        load(state);
728
        ((DefaultDataManager) this.getDataManager()).addObservers(this);
729
    }
730

    
731
    private void load(StateInformation state) {
732
        this.featureTypes = new ArrayList();
733
        this.defaultFeatureType = null;
734
        this.featureCount = null;
735

    
736
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
737
        try {
738
            intialize(dataManager, params);
739
        } catch (Throwable th) {
740
            state.setBreakingsCause(th);
741
        }
742

    
743
        try {
744
            DataStoreProvider prov = dataManager.createProvider(
745
                    getStoreProviderServices(),
746
                    params
747
            );
748
            setProvider(prov);
749
        } catch (Throwable th) {
750
            LOGGER.warn("Can't load store from state.", th);
751
            state.setBreakingsCause(th);
752
        }
753
        try {
754
            selection = (FeatureSelection) state.get("selection");
755
        } catch (Throwable th) {
756
            state.setBreakingsCause(th);
757
        }
758

    
759
        try {
760
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
761
            this.transforms.setFeatureStore(this);
762
            for (FeatureStoreTransform transform : this.transforms) {
763
                try {
764
                    transform.setUp();
765
                } catch (Throwable th) {
766
                    state.setBreakingsCause(th);
767
                }
768
            }
769
        } catch (Throwable th) {
770
            state.setBreakingsCause(th);
771
        }
772

    
773
        try {
774
            Map evaluatedAttributes = (Map) state.get("evaluatedAttributes");
775
            if ((evaluatedAttributes != null) && !evaluatedAttributes.isEmpty()) {
776
                Iterator iterEntries = evaluatedAttributes.entrySet().iterator();
777
                while (iterEntries.hasNext()) {
778
                    Entry entry = (Entry) iterEntries.next();
779
                    List attrs = (List) entry.getValue();
780
                    if (attrs.isEmpty()) {
781
                        continue;
782
                    }
783
                    int fTypePos = -1;
784
                    DefaultFeatureType type = null;
785
                    for (int i = 0; i < featureTypes.size(); i++) {
786
                        type = (DefaultFeatureType) featureTypes.get(i);
787
                        if (type.getId().equals(entry.getKey())) {
788
                            fTypePos = i;
789
                            break;
790
                        }
791
                    }
792
                    if (type == null) {
793
                        throw new PersistenceCantFindFeatureTypeException(
794
                                getName(), (String) entry.getKey());
795
                    }
796
                    DefaultEditableFeatureType eType = (DefaultEditableFeatureType) type.getEditable();
797
                    Iterator<FeatureAttributeDescriptor> iterAttr = attrs.iterator();
798
                    while (iterAttr.hasNext()) {
799
                        FeatureAttributeDescriptor attr = iterAttr.next();
800
                        eType.addLike(attr);
801
                    }
802
                    featureTypes.set(fTypePos, eType.getNotEditableCopy());
803

    
804
                }
805

    
806
            }
807
        } catch (Throwable th) {
808
            state.setBreakingsCause(th);
809
        }
810

    
811
        try {
812
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
813
            FeatureType ftype;
814

    
815
            if (defaultFeatureType == null
816
                    || defaultFeatureType.getId() == null
817
                    || !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
818

    
819
                ftype = getFeatureType(defaultFeatureTypeId);
820
                if (ftype == null) {
821
                    /*
822
                             * Un error en el m?todo de PostgreSQL getName(), hace que
823
                             * el nombre del featureType sea valor retornado por el getProviderName()
824
                             * De momento se pone este parche para apa?arlo y poder mantener compatibilidad
825
                             * con proyectos antiguos (2.1 y 2.2)
826
                     */
827
                    ftype = getFeatureType(getName());
828
                    if (ftype == null) {
829
                        throw new RuntimeException("Can't locate feature type");
830
                    }
831
                }
832
                defaultFeatureType = ftype;
833
            }
834
        } catch (Throwable th) {
835
            state.setBreakingsCause(th);
836
        }
837

    
838
        LOGGER.debug("load() broken:{}, {}, {}.",
839
                new Object[]{state.isBroken(), this.getProviderName(), params}
840
        );
841
    }
842

    
843
    public DataStoreProviderServices getStoreProviderServices() {
844
        return this;
845
    }
846

    
847
    public static void selfRegister(List<Exception> exs) {
848
        registerPersistenceDefinition();
849
        try {
850
            registerMetadataDefinition();
851
        } catch (MetadataException e) {
852
            exs.add(e);
853
        }
854
        try {
855
            DynObjectManager dynObjectManager = ToolsLocator.getDynObjectManager();
856
            dynObjectManager.registerTag(
857
                    DAL_USE_LARGE_SELECTION,
858
                    "Indicates whether the store should use a memory-based or a disk-based selection."
859
            ).setType(DataTypes.BOOLEAN);
860
            dynObjectManager.registerTag(
861
                    DAL_STORE_ENVELOPE,
862
                    "If specified, this geometry will be used to calculate the store envelope."
863
            ).setType(DataTypes.STRING);
864
        } catch (Exception e) {
865
            exs.add(e);
866
        }
867
    }
868

    
869
    private static void registerPersistenceDefinition() {
870
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
871
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
872
            DynStruct definition
873
                    = manager.addDefinition(DefaultFeatureStore.class,
874
                            PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
875
                            + " Persistent definition", null, null);
876
            definition.addDynFieldString("dataStoreName").setMandatory(true)
877
                    .setPersistent(true);
878

    
879
            definition.addDynFieldObject("parameters")
880
                    .setClassOfValue(DynObject.class).setMandatory(true)
881
                    .setPersistent(true);
882

    
883
            definition.addDynFieldObject("selection")
884
                    .setClassOfValue(FeatureSelection.class).setMandatory(false)
885
                    .setPersistent(true);
886

    
887
            definition.addDynFieldObject("transforms")
888
                    .setClassOfValue(DefaultFeatureStoreTransforms.class)
889
                    .setMandatory(true).setPersistent(true);
890

    
891
            definition.addDynFieldMap("evaluatedAttributes")
892
                    .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
893
                    .setMandatory(false).setPersistent(true);
894

    
895
            definition.addDynFieldString("defaultFeatureTypeId")
896
                    .setMandatory(true).setPersistent(true);
897
        }
898
    }
899

    
900
    private static void registerMetadataDefinition() throws MetadataException {
901
        MetadataManager manager = MetadataLocator.getMetadataManager();
902
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
903
            DynStruct metadataDefinition
904
                    = manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
905
            metadataDefinition.extend(manager
906
                    .getDefinition(DataStore.METADATA_DEFINITION_NAME));
907
        }
908
    }
909

    
910
    //
911
    // ====================================================================
912
    // Gestion de la seleccion
913
    //
914
    @Override
915
    public void setSelection(DataSet selection) throws DataException {
916
        this.setSelection((FeatureSet) selection);
917
    }
918

    
919
    @Override
920
    public DataSet createSelection() throws DataException {
921
        return createFeatureSelection();
922
    }
923

    
924
    @Override
925
    public DataSet getSelection() throws DataException {
926
        return this.getFeatureSelection();
927
    }
928

    
929
    @Override
930
    public void setSelection(FeatureSet selection) throws DataException {
931
        setSelection(selection, true);
932
    }
933

    
934
    public void setSelection(FeatureSet selection, boolean undoable)
935
            throws DataException {
936
        if (selection == null) {
937
            if (undoable) {
938
                throw new SelectionNotAllowedException(getName());
939
            }
940

    
941
        } else {
942
            if (selection.equals(this.selection)) {
943
                return;
944
            }
945
            if (!selection.isFromStore(this)) {
946
                throw new SelectionNotAllowedException(getName());
947
            }
948
        }
949

    
950
        if (this.selection != null) {
951
            this.selection.deleteObserver(this);
952
        }
953
        if (selection == null) {
954
            if (this.selection != null) {
955
                this.selection.dispose();
956
            }
957
            this.selection = null;
958
            return;
959
        }
960
        if (selection instanceof FeatureSelection) {
961
            if (undoable && isEditing()) {
962
                commands.selectionSet(this, this.selection,
963
                        (FeatureSelection) selection);
964
            }
965
            if (this.selection != null) {
966
                this.selection.dispose();
967
            }
968
            this.selection = (FeatureSelection) selection;
969
        } else {
970
            if (undoable && isEditing()) {
971
                commands.startComplex("_selectionSet");
972
            }
973
//            if (selection instanceof DefaultFeatureSelection) {
974
//                // FIXME: Estas lineas parece que no tienen sentido.
975
//                DefaultFeatureSelection defSelection = (DefaultFeatureSelection) selection;
976
//                defSelection.deselectAll(undoable);
977
//                defSelection.select(selection, undoable);
978
//            } else {
979
                if( this.selection == null ) {
980
                    this.selection = createDefaultFeatureSelection();
981
                }
982
                this.selection.deselectAll();
983
                this.selection.select(selection);
984
//            }
985
            if (undoable && isEditing()) {
986
                commands.endComplex();
987
            }
988
        }
989
        this.getFeatureSelection().addObserver(this);
990

    
991
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
992
    }
993

    
994
    @Override
995
    public FeatureSelection createFeatureSelection() throws DataException {
996
        FeatureType featureType = this.getDefaultFeatureTypeQuietly();
997
        if( featureType!=null ) {
998
            Tags tags = featureType.getTags();
999
            if( tags.has(DataManager.DAL_USE_LARGE_SELECTION) ) {
1000
                boolean useLargeSelection = tags.getBoolean(DataManager.DAL_USE_LARGE_SELECTION,true);
1001
                if( useLargeSelection ) {
1002
                    return createLargeFeatureSelection();
1003
                }
1004
                return this.provider.createFeatureSelection();
1005
            }
1006
        }
1007
        long maxSize = dataManager.getMaxSizeForSmallFeatureSelection();
1008
        if (this.provider.getFeatureCount() > maxSize) {
1009
            return createLargeFeatureSelection();
1010
        }
1011
        return this.provider.createFeatureSelection();
1012
    }
1013

    
1014
    @Override
1015
    public FeatureSelection createLargeFeatureSelection() throws DataException {
1016
        return new LargeFeatureSelection(this);
1017

    
1018
    }
1019

    
1020
    @Override
1021
    public FeatureSelection createMemoryFeatureSelection() throws DataException {
1022
        return this.provider.createFeatureSelection();
1023
    }
1024

    
1025
    @Override
1026
    public FeatureSelection getFeatureSelection() throws DataException {
1027
        if (selection == null) {
1028
            this.selection = createFeatureSelection();
1029
            this.selection.addObserver(this);
1030
        }
1031
        return selection;
1032
    }
1033

    
1034
    @Override
1035
    public boolean isFeatureSelectionEmpty() {
1036
        if( selection == null ) {
1037
            return true;
1038
        }
1039
        return selection.isEmpty();
1040
    }
1041
    
1042
    //
1043
    // ====================================================================
1044
    // Gestion de notificaciones
1045
    //
1046
    @Override
1047
    public FeatureStoreNotification notifyChange(FeatureStoreNotification storeNotification) {
1048
        if (delegateObservable != null) {
1049
            try {
1050
                delegateObservable.notifyObservers(storeNotification);
1051
            } catch (Throwable ex) {
1052
                LOGGER.warn("Problems notifying changes in the store '" + this.getName() + " (" + storeNotification.getType() + ").", ex);
1053
            }
1054
        }
1055
        return storeNotification;
1056
    }
1057

    
1058
    @Override
1059
    public FeatureStoreNotification notifyChange(String notification) {
1060
        return notifyChange(new DefaultFeatureStoreNotification(this, notification));
1061
    }
1062

    
1063
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode) {
1064
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode));
1065
    }
1066

    
1067
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode, int editMode) {
1068
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode, editMode));
1069
    }
1070

    
1071
    public FeatureStoreNotification notifyChange(String notification,
1072
            String editingSessionCode,
1073
            Iterator<FeatureReference> deleteds,
1074
            Iterator<EditableFeature> inserteds,
1075
            Iterator<EditableFeature> updateds,
1076
            Iterator<FeatureTypeChanged> featureTypesChanged,
1077
            boolean isSelectionCompromised) {
1078
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode,
1079
                deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised));
1080
    }
1081

    
1082
    @Override
1083
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
1084
        Feature f = null;
1085
        if (data != null) {
1086
            try {
1087
                f = createFeature(data);
1088
            } catch (Throwable ex) {
1089
                LOGGER.warn("Problems creating a feature to notifying changes in the store '" + this.getName() + " (" + notification + ").", ex);
1090
            }
1091
        }
1092
        return notifyChange(notification, f);
1093
    }
1094

    
1095
    public FeatureStoreNotification notifyChange(String notification, Feature feature) {
1096
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
1097
                feature));
1098
    }
1099

    
1100
    public FeatureStoreNotification notifyChange(String notification, Command command) {
1101
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
1102
                command));
1103
    }
1104

    
1105
    public FeatureStoreNotification notifyChange(String notification, EditableFeatureType type) {
1106
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
1107
                type));
1108
    }
1109

    
1110
    @Override
1111
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
1112
        return notifyChange(new DefaultFeatureStoreNotification(this,
1113
                DataStoreNotification.RESOURCE_CHANGED));
1114
    }
1115

    
1116
    //
1117
    // ====================================================================
1118
    // Gestion de bloqueos
1119
    //
1120
    @Override
1121
    public boolean isLocksSupported() {
1122
        return this.provider.isLocksSupported();
1123
    }
1124

    
1125
    @Override
1126
    public FeatureLocks getLocks() throws DataException {
1127
        if (!this.provider.isLocksSupported()) {
1128
            LOGGER.warn("Locks not supported");
1129
            return null;
1130
        }
1131
        if (locks == null) {
1132
            this.locks = this.provider.createFeatureLocks();
1133
        }
1134
        return locks;
1135
    }
1136

    
1137
    //
1138
    // ====================================================================
1139
    // Interface Observable
1140
    //
1141
    @Override
1142
    public void disableNotifications() {
1143
        this.delegateObservable.disableNotifications();
1144

    
1145
    }
1146

    
1147
    @Override
1148
    public void enableNotifications() {
1149
        this.delegateObservable.enableNotifications();
1150
    }
1151

    
1152
    @Override
1153
    public void beginComplexNotification() {
1154
        this.delegateObservable.beginComplexNotification();
1155

    
1156
    }
1157

    
1158
    @Override
1159
    public void endComplexNotification() {
1160
        this.delegateObservable.endComplexNotification();
1161

    
1162
    }
1163

    
1164
    @Override
1165
    public void addObserver(Observer observer) {
1166
        if (delegateObservable != null) {
1167
            this.delegateObservable.addObserver(observer);
1168
        }
1169
    }
1170

    
1171
    @Override
1172
    public void deleteObserver(Observer observer) {
1173
        if (delegateObservable != null) {
1174
            this.delegateObservable.deleteObserver(observer);
1175
        }
1176
    }
1177

    
1178
    @Override
1179
    public void deleteObservers() {
1180
        this.delegateObservable.deleteObservers();
1181

    
1182
    }
1183

    
1184
    //
1185
    // ====================================================================
1186
    // Interface Observer
1187
    //
1188
    // Usado para observar:
1189
    // - su seleccion
1190
    // - sus bloqueos
1191
    // - sus recursos
1192
    //
1193
    @Override
1194
    public void update(Observable observable, Object notification) {
1195
        if (observable instanceof FeatureSet) {
1196
            if (observable == this.selection) {
1197
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1198
            } else if (observable == this.locks) {
1199
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1200
            }
1201

    
1202
        } else if (observable instanceof FeatureStoreProvider) {
1203
            if (observable == this.provider) {
1204

    
1205
            }
1206
        } else if (observable instanceof FeatureReferenceSelection) {
1207
            if (notification instanceof String) {
1208
                this.notifyChange((String) notification);
1209
            }
1210
        }
1211
    }
1212

    
1213
    //
1214
    // ====================================================================
1215
    // Edicion
1216
    //
1217
    private void newVersionOfUpdate() {
1218
        this.versionOfUpdate++;
1219
    }
1220

    
1221
    private long currentVersionOfUpdate() {
1222
        return this.versionOfUpdate;
1223
    }
1224

    
1225
    private void checkInEditingMode() throws NeedEditingModeException {
1226
        if (mode != MODE_FULLEDIT) {
1227
            throw new NeedEditingModeException(this.getName());
1228
        }
1229
    }
1230

    
1231
    private void checkNotInAppendMode() throws IllegalStateException {
1232
        if (mode == MODE_APPEND) {
1233
            throw new IllegalStateException("Error: store "
1234
                    + this.getFullName() + " is in append mode");
1235
        }
1236
    }
1237

    
1238
    private void checkIsOwnFeature(Feature feature)
1239
            throws IllegalFeatureException {
1240
        if (((DefaultFeature) feature).getStore() != this) {
1241
            throw new IllegalFeatureException(this.getName());
1242
        }
1243
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1244
        // fixFeatureType((DefaultFeatureType) feature.getType());
1245
    }
1246

    
1247
    private void exitEditingMode() {
1248
        if (commands != null) {
1249
            try {
1250
                commands.clear();
1251
            } catch (Exception ex) {
1252
                LOGGER.trace("Can't clear commands", ex);
1253
            }
1254
            commands = null;
1255
        }
1256

    
1257
        if (featureTypeManager != null) {
1258
            DisposeUtils.disposeQuietly(featureTypeManager);
1259
            featureTypeManager = null;
1260

    
1261
        }
1262

    
1263
        // TODO implementar un dispose para estos dos
1264
        featureManager = null;
1265
        spatialManager = null;
1266

    
1267
        featureCount = null;
1268

    
1269
        mode = MODE_QUERY;
1270
        hasStrongChanges = true; // Lo deja a true por si las moscas
1271

    
1272
        this.editingSessionCode = null;
1273
    }
1274

    
1275
    @Override
1276
    synchronized public void edit() throws DataException {
1277
        edit(MODE_FULLEDIT);
1278
    }
1279

    
1280
    @Override
1281
    synchronized public void edit(int mode) throws DataException {
1282
        LOGGER.debug("Starting editing in mode: {}", mode);
1283
        String newSessionCode = this.createUniqueID();
1284
        try {
1285
            if (this.mode != MODE_QUERY) {
1286
                throw new AlreadyEditingException(this.getName());
1287
            }
1288
            if (!this.provider.supportsAppendMode()) {
1289
                mode = MODE_FULLEDIT;
1290
            }
1291
            switch (mode) {
1292
                case MODE_QUERY:
1293
                    throw new IllegalStateException(this.getName());
1294

    
1295
                case MODE_FULLEDIT:
1296
                    if (!this.transforms.isEmpty()) {
1297
                        throw new IllegalStateException(this.getName());
1298
                    }
1299
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1300
                            newSessionCode, mode).isCanceled()) {
1301
                        return;
1302
                    }
1303
                    this.editingSessionCode = newSessionCode;
1304
                    invalidateIndexes();
1305
                    featureManager = new FeatureManager(this);
1306
                    featureTypeManager = new FeatureTypeManager(this);
1307
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
1308

    
1309
                    commands = new DefaultFeatureCommandsStack(
1310
                            this, featureManager,
1311
                            spatialManager, featureTypeManager);
1312
                    this.mode = MODE_FULLEDIT;
1313
                    hasStrongChanges = false;
1314
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING, newSessionCode, this.mode);
1315
                    break;
1316

    
1317
                case MODE_APPEND:
1318
                    if (!this.transforms.isEmpty()) {
1319
                        throw new IllegalStateException(this.getName());
1320
                    }
1321
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1322
                            newSessionCode, mode).isCanceled()) {
1323
                        return;
1324
                    }
1325
                    this.editingSessionCode = newSessionCode;
1326
                    invalidateIndexes();
1327
                    this.provider.beginAppend();
1328
                    this.mode = MODE_APPEND;
1329
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1330
                            newSessionCode, this.mode);
1331
                    break;
1332
                case MODE_PASS_THROUGH:
1333
                    if (!this.provider.supportsPassThroughMode()) {
1334
                        throw new IllegalStateException(this.getName());
1335
                    }
1336
                    if (!this.transforms.isEmpty()) {
1337
                        throw new IllegalStateException(this.getName());
1338
                    }
1339
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1340
                            newSessionCode, mode).isCanceled()) {
1341
                        return;
1342
                    }
1343
                    this.editingSessionCode = newSessionCode;
1344
                    invalidateIndexes();
1345
                    this.mode = MODE_PASS_THROUGH;
1346
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1347
                            newSessionCode, this.mode);
1348
                    break;
1349

    
1350
            }
1351
        } catch (Exception e) {
1352
            try {
1353
                if (this.mode != MODE_QUERY) {
1354
                    exitEditingMode();
1355
                }
1356
                notifyChange(FeatureStoreNotification.FAILED_STARTEDITING,
1357
                        newSessionCode, mode);
1358
            } catch (Throwable th) {
1359
                LOGGER.warn("Can't cleanup after error in start editing.", th);
1360
            }
1361
            throw new StoreEditException(e, this.getName());
1362
        }
1363
    }
1364

    
1365
    private void invalidateIndexes() {
1366
        setIndexesValidStatus(false);
1367
    }
1368

    
1369
    private void setIndexesValidStatus(boolean valid) {
1370
        FeatureIndexes theIndexes = getIndexes();
1371
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1372
                ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1373
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1374
            FeatureIndex index = (FeatureIndex) iterator.next();
1375
            if (index instanceof FeatureIndexProviderServices) {
1376
                FeatureIndexProviderServices indexServices
1377
                        = (FeatureIndexProviderServices) index;
1378
                indexServices.setValid(valid);
1379
            }
1380
        }
1381
    }
1382

    
1383
    private void updateIndexes() throws FeatureIndexException {
1384
        FeatureIndexes theIndexes = getIndexes();
1385
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1386
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1387
            FeatureIndex index = (FeatureIndex) iterator.next();
1388
            if (index instanceof FeatureIndexProviderServices) {
1389
                FeatureIndexProviderServices indexServices
1390
                        = (FeatureIndexProviderServices) index;
1391
                indexServices.fill(true, null);
1392
            }
1393
        }
1394
    }
1395

    
1396
    private void waitForIndexes() {
1397
        FeatureIndexes theIndexes = getIndexes();
1398
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1399
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1400
            FeatureIndex index = (FeatureIndex) iterator.next();
1401
            if (index instanceof FeatureIndexProviderServices) {
1402
                FeatureIndexProviderServices indexServices
1403
                        = (FeatureIndexProviderServices) index;
1404
                indexServices.waitForIndex();
1405
            }
1406
        }
1407
    }
1408

    
1409
    private void disposeIndexes() {
1410
        FeatureIndexes theIndexes = getIndexes();
1411
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1412
        if (theIndexes == null) {
1413
            return;
1414
        }
1415
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1416
            FeatureIndex index = (FeatureIndex) iterator.next();
1417
            if (index instanceof FeatureIndexProviderServices) {
1418
                FeatureIndexProviderServices indexServices
1419
                        = (FeatureIndexProviderServices) index;
1420
                indexServices.dispose();
1421
            }
1422
        }
1423
    }
1424

    
1425
    @Override
1426
    public boolean isEditing() {
1427
        return mode == MODE_FULLEDIT;
1428
    }
1429

    
1430
    @Override
1431
    public boolean isAppending() {
1432
        return mode == MODE_APPEND;
1433
    }
1434

    
1435
    @Override
1436
    synchronized public void update(EditableFeatureType type)
1437
            throws DataException {
1438
        try {
1439
            if (type == null) {
1440
                throw new NullFeatureTypeException(getName());
1441
            }
1442

    
1443
            switch (this.mode) {
1444
                case MODE_QUERY:
1445
                    if (type.hasOnlyMetadataChanges(this.defaultFeatureType)) {
1446
                        if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1447
                            return;
1448
                        }
1449
                        FeatureType theType = type.getNotEditableCopy();
1450
                        if (defaultFeatureType.getId().equals(theType.getId())) {
1451
                            defaultFeatureType = theType;
1452
                        }
1453
                        List newtypes = new ArrayList();
1454
                        for (FeatureType featureType : this.featureTypes) {
1455
                            if (featureType.getId().equals(theType.getId())) {
1456
                                newtypes.add(theType);
1457
                            } else {
1458
                                newtypes.add(featureType);
1459
                            }
1460
                        }
1461
                        this.featureTypes = newtypes;
1462
                        saveDALFile();
1463
                        notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1464
                    }
1465

    
1466
                    break;
1467
                case MODE_FULLEDIT:
1468
                    if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1469
                        return;
1470
                    }
1471
                    newVersionOfUpdate();
1472

    
1473
                    FeatureType oldt = type.getSource().getCopy();
1474
                    FeatureType newt = type.getCopy();
1475
                    commands.update(newt, oldt);
1476
                    hasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1477
                    notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1478
                    break;
1479
                case MODE_APPEND:
1480
                case MODE_PASS_THROUGH:
1481
                    throw new NeedEditingModeException(this.getName());
1482

    
1483
            }
1484
        } catch (Exception e) {
1485
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1486
        }
1487
    }
1488

    
1489
    @Override
1490
    public void delete(Feature feature) throws DataException {
1491
        switch (this.mode) {
1492
            case MODE_PASS_THROUGH:
1493
                checkIsOwnFeature(feature);
1494
                if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1495
                    return;
1496
                }
1497
                this.provider.passThroughDelete((FeatureReferenceProviderServices) feature.getReference());
1498
                notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1499
                break;
1500
            default:
1501
                this.commands.delete(feature);
1502
                break;
1503

    
1504
        }
1505
    }
1506

    
1507
    @Override
1508
    public void delete(String filter) {
1509
        if (StringUtils.isBlank(filter)) {
1510
            return;
1511
        }
1512
        this.delete(ExpressionUtils.createExpression(filter));
1513
    }
1514

    
1515
    @Override
1516
    public void delete(Expression filter) {
1517
        // TODO: Optimizar pasandolo directamente al proveedor si no estamos en edicion y lo soporta.
1518
        if (filter == null) {
1519
            return;
1520
        }
1521
        boolean pendingFinishEditing = false;
1522
        DisposableFeatureSetIterable features = null;
1523
        try {
1524
            switch (this.mode) {
1525
                case MODE_QUERY:
1526
                    pendingFinishEditing = true;
1527
                    this.edit();
1528
                    break;
1529
                case MODE_APPEND:
1530
                    throw new IllegalStateException("Delete not allowed in append mode.");
1531
                case MODE_FULLEDIT:
1532
                    break;
1533
                case MODE_PASS_THROUGH:
1534
                    this.provider.passThroughDelete(filter);
1535
                    return;
1536
                default:
1537
                    throw new IllegalStateException("Mode " + this.mode + " not supported.");
1538
            }
1539

    
1540
            FeatureSet fset = this.getFeatureSet(filter);
1541
            features = fset.iterable();
1542
            for (Feature f : features) {
1543
                fset.delete(f);
1544
            }
1545
        } catch (DataException ex) {
1546
            throw new DataRuntimeException(ex.getFormatString(), ex.getMessageKey(), ex.getCode()) {
1547
            };
1548
        } catch (Exception ex) {
1549
            throw new RuntimeException("Can't delete features (" + filter.getPhrase() + ").", ex);
1550
        } finally {
1551
            if (pendingFinishEditing) {
1552
                this.finishEditingQuietly();
1553
            }
1554
            DisposeUtils.disposeQuietly(features);
1555
        }
1556
    }
1557

    
1558
    synchronized public void doDelete(Feature feature) throws DataException {
1559
        if (feature == null) {
1560
            throw new IllegalArgumentException("feature argument can't be null.");
1561
        }
1562
        try {
1563
            checkInEditingMode();
1564
            checkIsOwnFeature(feature);
1565
            if (feature instanceof EditableFeature && !((EditableFeature)feature).isUpdatable()) {
1566
                //La feature no est? persistida en disco
1567
                throw new StoreDeleteEditableFeatureException(getName());
1568
            }
1569
            if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1570
                return;
1571
            }
1572

    
1573
            //Update the featureManager and the spatialManager
1574
            featureManager.delete(feature);
1575
            spatialManager.deleteFeature(feature);
1576

    
1577
            newVersionOfUpdate();
1578
            hasStrongChanges = true;
1579
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1580
        } catch (Exception e) {
1581
            throw new StoreDeleteFeatureException(e, this.getName());
1582
        }
1583
    }
1584

    
1585
    @Override
1586
    public synchronized void insert(FeatureSet set) throws DataException {
1587
        switch (mode) {
1588
            case MODE_QUERY:
1589
                throw new NeedEditingModeException(this.getName());
1590

    
1591
            case MODE_APPEND:
1592
            case MODE_FULLEDIT:
1593
            case MODE_PASS_THROUGH:
1594
            try {
1595
                set.accept((Object obj) -> {
1596
                    EditableFeature ef = createNewFeature((Feature) obj);
1597
                    insert(ef);
1598
                });
1599
            } catch (BaseException ex) {
1600
                throw new StoreInsertFeatureException(ex, this.getName());
1601
            }
1602
            break;
1603
        }
1604
    }
1605

    
1606
    private static EditableFeature lastChangedFeature = null;
1607

    
1608
    @Override
1609
    public synchronized void insert(EditableFeature feature)
1610
            throws DataException {
1611
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1612
        try {
1613
            switch (mode) {
1614
                case MODE_QUERY:
1615
                    throw new NeedEditingModeException(this.getName());
1616

    
1617
                case MODE_APPEND:
1618
                    checkIsOwnFeature(feature);
1619
                    if (feature.isUpdatable()) {
1620
                        throw new NoNewFeatureInsertException(this.getName());
1621
                    }
1622
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1623
                        return;
1624
                    }
1625
                    this.featureCount = null;
1626
                    feature.validate(CHECK_RULES_AT_EDITING);
1627
                    provider.append(((DefaultEditableFeature) feature).getData());
1628
                    hasStrongChanges = true;
1629
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1630
                    break;
1631

    
1632
                case MODE_FULLEDIT:
1633
                    if (feature.isUpdatable()) {
1634
                        throw new NoNewFeatureInsertException(this.getName());
1635
                    }
1636
                    feature.validate(CHECK_RULES_AT_EDITING);
1637
                    commands.insert(feature);
1638
                    break;
1639

    
1640
                case MODE_PASS_THROUGH:
1641
                    checkIsOwnFeature(feature);
1642
                    if (feature.isUpdatable()) {
1643
                        throw new NoNewFeatureInsertException(this.getName());
1644
                    }
1645
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1646
                        return;
1647
                    }
1648
                    feature.validate(CHECK_RULES_AT_EDITING);
1649
                    this.provider.passThroughInsert(((DefaultEditableFeature) feature).getData());
1650
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1651
                    break;
1652
            }
1653
        } catch (Exception e) {
1654
            throw new StoreInsertFeatureException(e, this.getName());
1655
        }
1656
    }
1657

    
1658
    synchronized public void doInsert(EditableFeature feature)
1659
            throws DataException {
1660
        checkIsOwnFeature(feature);
1661

    
1662
        waitForIndexes();
1663

    
1664
        if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1665
            return;
1666
        }
1667
        newVersionOfUpdate();
1668
        if ((lastChangedFeature == null)
1669
                || (lastChangedFeature.getSource() != feature.getSource())) {
1670
            lastChangedFeature = feature;
1671
            feature.validate(CHECK_RULES_AT_EDITING);
1672
            lastChangedFeature = null;
1673
        }
1674
        //Update the featureManager and the spatialManager
1675
        ((DefaultFeature) feature).setInserted(true);
1676
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1677

    
1678
        featureManager.add(feature);
1679
        spatialManager.insertFeature(newFeature);
1680

    
1681
        hasStrongChanges = true;
1682
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1683
    }
1684

    
1685
    @Override
1686
    public void update(EditableFeature feature)
1687
            throws DataException {
1688
        switch (this.mode) {
1689
            case MODE_PASS_THROUGH:
1690
                checkIsOwnFeature(feature);
1691
                if (!feature.isUpdatable()) {
1692
                    throw new NoNewFeatureInsertException(this.getName());
1693
                }
1694
                if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1695
                    return;
1696
                }
1697
                feature.validate(CHECK_RULES_AT_EDITING);
1698
                this.provider.passThroughUpdate(((DefaultEditableFeature) feature).getData());
1699
                notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1700
                break;
1701
            case MODE_FULLEDIT:
1702
                if (feature.isUpdatable()) {
1703
                    commands.update(feature, feature.getSource());
1704
                    return;
1705
                }
1706
                // FIXME: Deberiamos lanzar aqui un error en lugar de hacer el insert.
1707
                //        O lanzar un mensaje al log?
1708
                insert(feature);
1709
                break;
1710
            default:
1711
                throw new NeedEditingModeException(this.getName());
1712
        }
1713
    }
1714

    
1715
    @Override
1716
    public void update(Object... parameters) throws DataException {
1717
        if (parameters.length == 1) {
1718
            Object param0 = parameters[0];
1719
            if (param0 instanceof EditableFeature) {
1720
                this.update((EditableFeature) param0);
1721
            } else if (param0 instanceof EditableFeatureType) {
1722
                this.update((EditableFeatureType) param0);
1723
            } else {
1724
                throw new IllegalArgumentException("Type of first parameter isn't supported");
1725
            }
1726
            return;
1727
        }
1728

    
1729
        Expression filter = null;
1730
        long end = parameters.length;
1731
        if (parameters.length % 2 == 1) { //IMPAR
1732
            Object param = parameters[parameters.length - 1];
1733
            if (param != null) {
1734
                if (param instanceof Expression) {
1735
                    filter = (Expression) param;
1736
                } else {
1737
                    filter = ExpressionUtils.createExpression(param.toString());
1738
                }
1739
            }
1740
        } else {
1741
            end = parameters.length - 1;
1742
        }
1743

    
1744
        switch (this.mode) {
1745
            case MODE_PASS_THROUGH:
1746
                this.provider.passThroughUpdate(
1747
                        //                    this.getName(), 
1748
                        parameters,
1749
                        filter);
1750
                break;
1751
            case MODE_FULLEDIT:
1752
                FeatureSet set = this.getFeatureSet(filter);
1753
                DisposableIterator it = set.fastIterator();
1754
                while (it.hasNext()) {
1755
                    Feature feature = (Feature) it.next();
1756
                    EditableFeature ef = feature.getEditable();
1757
                    for (int i = 0; i < end; i += 2) {
1758
                        String name = (String) parameters[i];
1759
                        Object value = parameters[i + 1];
1760
                        ef.set(name, value);
1761
                    }
1762
                    set.update(ef);
1763
                }
1764
                DisposeUtils.disposeQuietly(it);
1765
                DisposeUtils.disposeQuietly(set);
1766
                break;
1767
            default:
1768
                throw new NeedEditingModeException(this.getName());
1769
        }
1770
    }
1771

    
1772
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1773
            throws DataException {
1774
        try {
1775
            checkInEditingMode();
1776
            checkIsOwnFeature(feature);
1777
            if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1778
                return;
1779
            }
1780
            newVersionOfUpdate();
1781
            if ((lastChangedFeature == null)
1782
                    || (lastChangedFeature.getSource() != feature.getSource())) {
1783
                lastChangedFeature = feature;
1784
                feature.validate(CHECK_RULES_AT_EDITING);
1785
                lastChangedFeature = null;
1786
            }
1787

    
1788
            //Update the featureManager and the spatialManager
1789
            Feature newf = feature.getNotEditableCopy();
1790
            featureManager.update(feature, oldFeature);
1791
            spatialManager.updateFeature(newf, oldFeature);
1792

    
1793
            hasStrongChanges = true;
1794
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1795
        } catch (Exception e) {
1796
            throw new StoreUpdateFeatureException(e, this.getName());
1797
        }
1798
    }
1799

    
1800
    @Override
1801
    synchronized public void redo() throws RedoException {
1802
        Command redo = commands.getNextRedoCommand();
1803
        try {
1804
            checkInEditingMode();
1805
        } catch (NeedEditingModeException ex) {
1806
            throw new RedoException(redo, ex);
1807
        }
1808
        if (notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled()) {
1809
            return;
1810
        }
1811
        newVersionOfUpdate();
1812
        commands.redo();
1813
        hasStrongChanges = true;
1814
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1815
    }
1816

    
1817
    @Override
1818
    synchronized public void undo() throws UndoException {
1819
        Command undo = commands.getNextUndoCommand();
1820
        try {
1821
            checkInEditingMode();
1822
        } catch (NeedEditingModeException ex) {
1823
            throw new UndoException(undo, ex);
1824
        }
1825
        if (notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled()) {
1826
            return;
1827
        }
1828
        newVersionOfUpdate();
1829
        commands.undo();
1830
        hasStrongChanges = true;
1831
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1832
    }
1833

    
1834
    @Override
1835
    public List getRedoInfos() {
1836
        if (isEditing() && (commands != null)) {
1837
            return commands.getRedoInfos();
1838
        } else {
1839
            return null;
1840
        }
1841
    }
1842

    
1843
    @Override
1844
    public List getUndoInfos() {
1845
        if (isEditing() && (commands != null)) {
1846
            return commands.getUndoInfos();
1847
        } else {
1848
            return null;
1849
        }
1850
    }
1851

    
1852
    public synchronized FeatureCommandsStack getCommandsStack()
1853
            throws DataException {
1854
        checkInEditingMode();
1855
        return commands;
1856
    }
1857

    
1858
    @Override
1859
    public boolean cancelEditingQuietly() {
1860
        try {
1861
            this.cancelEditing();
1862
            return true;
1863
        } catch (Exception ex) {
1864
            LOGGER.debug("Can't cancel editing", ex);
1865
            return false;
1866
        }
1867
    }
1868

    
1869
    @Override
1870
    synchronized public void cancelEditing() throws DataException {
1871
        if (spatialManager != null) {
1872
            spatialManager.cancelModifies();
1873
        }
1874
        try {
1875
            switch (mode) {
1876
                case MODE_QUERY:
1877
                    throw new NeedEditingModeException(this.getName());
1878

    
1879
                case MODE_APPEND:
1880
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1881
                        return;
1882
                    }
1883
                    provider.abortAppend();
1884
                    exitEditingMode();
1885
                    ((FeatureSelection) this.getSelection()).deselectAll();
1886
                    updateIndexes();
1887
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1888
                    break;
1889

    
1890
                case MODE_FULLEDIT:
1891
                    boolean clearSelection = this.hasStrongChanges;
1892
                    if (this.selection instanceof FeatureReferenceSelection) {
1893
                        clearSelection = this.hasStrongChanges || this.featureManager.hasNews();
1894
                    }
1895
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING,this.editingSessionCode).isCanceled()) {
1896
                        return;
1897
                    }
1898
                    exitEditingMode();
1899
                    if (clearSelection) {
1900
                        ((FeatureSelection) this.getSelection()).deselectAll();
1901
                    }
1902
                    updateIndexes();
1903
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING,this.editingSessionCode);
1904
                    break;
1905

    
1906
                case MODE_PASS_THROUGH:
1907
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1908
                        return;
1909
                    }
1910
                    exitEditingMode();
1911
                    ((FeatureSelection) this.getSelection()).deselectAll();
1912
                    updateIndexes();
1913
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1914
                    break;
1915
            }
1916
        } catch (Exception e) {
1917
            throw new StoreCancelEditingException(e, this.getName());
1918
        }
1919
    }
1920

    
1921
    @Override
1922
    public boolean finishEditingQuietly() {
1923
        try {
1924
            this.finishEditing();
1925
            return true;
1926
        } catch (Exception ex) {
1927
            LOGGER.debug("Can't finish editing", ex);
1928
            return false;
1929
        }
1930
    }
1931

    
1932
    @Override
1933
    synchronized public void finishEditing() throws DataException {
1934
        LOGGER.debug("finish editing of mode: {}", mode);
1935
        try {
1936

    
1937
            /*
1938
             * Selection needs to be cleared when editing stops
1939
             * to prevent conflicts with selection remaining from
1940
             * editing mode.
1941
             */
1942
//            ((FeatureSelection) this.getSelection()).deselectAll();
1943
            Map<String, List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1944
            switch (mode) {
1945
                case MODE_QUERY:
1946
                    throw new NeedEditingModeException(this.getName());
1947

    
1948
                case MODE_APPEND:
1949
                    if (selection != null) {
1950
                        selection = null;
1951
                    }
1952
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, this.editingSessionCode).isCanceled()) {
1953
                        return;
1954
                    }
1955
                    saveDALFile();
1956
                    provider.endAppend();
1957
                    exitEditingMode();
1958
                    this.updateComputedFields(computedFields);
1959
                    loadDALFile();
1960
                    updateIndexes();
1961
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING, this.editingSessionCode);
1962
                    break;
1963

    
1964
                case MODE_FULLEDIT:
1965
                    if (featureManager.hasChanges() || featureTypeManager.hasChanges()) {
1966
                        if (hasStrongChanges && !this.allowWrite()) {
1967
                            throw new WriteNotAllowedException(getName());
1968
                        }
1969
                        if (notifyChange(FeatureStoreNotification.PREPARING_FINISHEDITING,
1970
                                this.editingSessionCode).isCanceled()) {
1971
                            return;
1972
                        }
1973
                        if (hasStrongChanges) {
1974
                            validateFeaturesAtFinishEditing();
1975
                        }
1976
                        if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING,
1977
                                this.editingSessionCode,
1978
                                featureManager.getDeleted(),
1979
                                featureManager.getInsertedFeatures(),
1980
                                featureManager.getUpdatedFeatures(),
1981
                                featureTypeManager.getFeatureTypesChanged().iterator(),
1982
                                featureManager.isSelectionCompromised()).isCanceled()) {
1983
                            return;
1984
                        }
1985
                        saveDALFile();
1986
                        if (featureManager.isSelectionCompromised() && selection != null) {
1987
                            selection = null;
1988
                        }
1989
                        if (hasStrongChanges) {
1990
                            /*
1991
                         * This will throw a PerformEditingExceptionif the provider
1992
                         * does not accept the changes (for example, an invalid field name)
1993
                             */
1994
                            provider.performChanges(featureManager.getDeleted(),
1995
                                    featureManager.getInserted(),
1996
                                    featureManager.getUpdated(),
1997
                                    removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1998

    
1999
                        }
2000
                        this.updateComputedFields(computedFields);
2001
                        exitEditingMode();
2002
                        loadDALFile();
2003
                        updateIndexes();
2004
                        notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING, this.editingSessionCode);
2005
                    } else {
2006
                        exitEditingMode();
2007
                    }
2008
                    break;
2009
                case MODE_PASS_THROUGH:
2010
                    if (selection != null) {
2011
                        selection = null;
2012
                    }
2013
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, this.editingSessionCode).isCanceled()) {
2014
                        return;
2015
                    }
2016
                    exitEditingMode();
2017
                    updateIndexes();
2018
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING, this.editingSessionCode);
2019
                    break;
2020
            }
2021
        } catch (ValidateFeaturesException | WriteNotAllowedException ex) {
2022
            // Don't notify failed.
2023
            throw ex;
2024
        } catch (PerformEditingException pee) {
2025
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING, this.editingSessionCode);
2026
            throw new WriteException(provider.getSourceId().toString(), pee);
2027
        } catch (Exception e) {
2028
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING, this.editingSessionCode);
2029
            throw new FinishEditingException(e);
2030
        }
2031
    }
2032

    
2033
    @Override
2034
    public String getEditingSession() {
2035
        return this.editingSessionCode;
2036
    }
2037

    
2038
    private Map<String, List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
2039
        Map<String, List<FeatureAttributeDescriptor>> r = new HashMap<>();
2040

    
2041
        List<FeatureType> theTypes = new ArrayList<>();
2042
        theTypes.addAll(this.getFeatureTypes());
2043
        theTypes.add(this.getDefaultFeatureType());
2044
        for (int n = 0; n < theTypes.size(); n++) {
2045
            FeatureType type = theTypes.get(n);
2046
            for (FeatureAttributeDescriptor attrdesc : type) {
2047
                FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
2048
                if (emulator != null) {
2049
                    List<FeatureAttributeDescriptor> l = r.get(type.getId());
2050
                    if (l == null) {
2051
                        l = new ArrayList<>();
2052
                        r.put(type.getId(), l);
2053
                    }
2054
                    l.add(attrdesc);
2055
                }
2056
            }
2057
        }
2058
        return r;
2059
    }
2060

    
2061
    private void updateComputedFields(Map<String, List<FeatureAttributeDescriptor>> computedFields) throws DataException {
2062

    
2063
        List<FeatureType> theTypes = new ArrayList<>();
2064
        theTypes.addAll(this.getFeatureTypes());
2065
        theTypes.add(this.getDefaultFeatureType());
2066
        for (int n = 0; n < theTypes.size(); n++) {
2067
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
2068
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
2069
            if (x != null && !x.isEmpty()) {
2070
                for (FeatureAttributeDescriptor attrdesc : x) {
2071
                    if (type.get(attrdesc.getName()) == null) {
2072
                        type.add(attrdesc);
2073
                    }
2074
                }
2075
            }
2076
        }
2077

    
2078
    }
2079

    
2080
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
2081
        // FIXME: Falta por implementar
2082
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
2083
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
2084
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
2085
//                if (attributeDescriptor.isComputed()) {
2086
//                    target.remove(attributeDescriptor.getName());
2087
//                }
2088
//            }
2089
//        }
2090
        return ftypes;
2091
    }
2092

    
2093
    private void saveDALFile() {
2094
        if( this.ignoreDALResource ) {
2095
            return;
2096
        }
2097
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2098
        ResourcesStorage theResourcesStorage = null;
2099
        try {
2100
            theResourcesStorage = this.getResourcesStorage();
2101
            if (theResourcesStorage == null || theResourcesStorage.isReadOnly()) {
2102
                return;
2103
            }
2104
            resource = theResourcesStorage.getResource("dal");
2105
            if (resource == null || resource.isReadOnly()) {
2106
                return;
2107
            }
2108
            DALFile dalFile = DALFile.getDALFile();
2109
            dalFile.setStore(this);
2110
            if (!dalFile.isEmpty()) {
2111
                dalFile.write(resource);
2112
            }
2113
        } catch (Throwable ex) {
2114
            LOGGER.warn("Can't save DAL resource", ex);
2115
        } finally {
2116
            IOUtils.closeQuietly(resource);
2117
            DisposeUtils.disposeQuietly(theResourcesStorage);
2118
        }
2119
    }
2120

    
2121
    private void loadDALFile() {
2122
        if( this.ignoreDALResource ) {
2123
            return;
2124
        }
2125
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2126
        ResourcesStorage theResourcesStorage = null;
2127
        try {
2128
            theResourcesStorage = this.getResourcesStorage();
2129
            if (theResourcesStorage == null) {
2130
                return;
2131
            }
2132
            resource = theResourcesStorage.getResource("dal");
2133
            if (resource == null || !resource.exists()) {
2134
                return;
2135
            }
2136
            DALFile dalFile = DALFile.getDALFile(resource);
2137
            if (!dalFile.isEmpty()) {
2138
                dalFile.updateStore(this);
2139
            }
2140
        } catch (Throwable ex) {
2141
            if (resource == null || theResourcesStorage == null) {
2142
                if (theResourcesStorage == null) {
2143
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=null)", ex);
2144
                } else {
2145
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2146
                }
2147
            } else {
2148
                LOGGER.warn("Can't load DAL resource (resname=" + resource.getName() + ", resurl=" + Objects.toString(resource.getURL()) + ", storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2149
            }
2150
        } finally {
2151
            IOUtils.closeQuietly(resource);
2152
            DisposeUtils.disposeQuietly(theResourcesStorage);
2153
        }
2154
    }
2155

    
2156
    /**
2157
     * Save changes in the provider without leaving the edit mode. Do not call
2158
     * observers to communicate a change of ediding mode. The operation's
2159
     * history is eliminated to prevent inconsistencies in the data.
2160
     *
2161
     * @throws DataException
2162
     */
2163
    @Override
2164
    synchronized public void commitChanges() throws DataException {
2165
        LOGGER.debug("commitChanges of mode: {}", mode);
2166
        if (!canCommitChanges()) {
2167
            throw new WriteNotAllowedException(getName());
2168
        }
2169
        try {
2170
            switch (mode) {
2171
                case MODE_QUERY:
2172
                    throw new NeedEditingModeException(this.getName());
2173

    
2174
                case MODE_APPEND:
2175
                    this.provider.endAppend();
2176
                    exitEditingMode();
2177
                    invalidateIndexes();
2178
                    this.provider.beginAppend();
2179
                    break;
2180

    
2181
                case MODE_FULLEDIT:
2182
                    if (hasStrongChanges && !this.allowWrite()) {
2183
                        throw new WriteNotAllowedException(getName());
2184
                    }
2185
                    // FIXME: OOhh!!!! no se disparan eventos, VCSGis no se entera de estos cambios.
2186
                    if (hasStrongChanges) {
2187
                        validateFeaturesAtFinishEditing();
2188
                        provider.performChanges(featureManager.getDeleted(),
2189
                                featureManager.getInserted(),
2190
                                featureManager.getUpdated(),
2191
                                removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2192
                    }
2193
                    invalidateIndexes();
2194
                    featureManager = new FeatureManager(this);
2195
                    featureTypeManager = new FeatureTypeManager(this);
2196
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
2197

    
2198
                    commands
2199
                            = new DefaultFeatureCommandsStack(this, featureManager,
2200
                                    spatialManager, featureTypeManager);
2201
                    featureCount = null;
2202
                    hasStrongChanges = false;
2203
                    break;
2204
            }
2205
        } catch (Exception e) {
2206
            throw new FinishEditingException(e);
2207
        }
2208
    }
2209

    
2210
    @Override
2211
    synchronized public boolean canCommitChanges() throws DataException {
2212
        if (!this.allowWrite()) {
2213
            return false;
2214
        }
2215
        switch (mode) {
2216
            default:
2217
            case MODE_QUERY:
2218
                return false;
2219

    
2220
            case MODE_APPEND:
2221
                return true;
2222

    
2223
            case MODE_FULLEDIT:
2224
                List types = this.getFeatureTypes();
2225
                for (int i = 0; i < types.size(); i++) {
2226
                    Object type = types.get(i);
2227
                    if (type instanceof DefaultEditableFeatureType) {
2228
                        if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
2229
                            return false;
2230
                        }
2231
                    }
2232
                }
2233
                return true;
2234
        }
2235
    }
2236

    
2237
    @Override
2238
    public void beginEditingGroup(String description)
2239
            throws NeedEditingModeException {
2240
        checkInEditingMode();
2241
        commands.startComplex(description);
2242
    }
2243

    
2244
    @Override
2245
    public void endEditingGroup() throws NeedEditingModeException {
2246
        checkInEditingMode();
2247
        commands.endComplex();
2248
    }
2249

    
2250
    @Override
2251
    public boolean isAppendModeSupported() {
2252
        return this.provider.supportsAppendMode();
2253
    }
2254

    
2255
    @Override
2256
    public void export(DataServerExplorer explorer, String provider,
2257
            NewFeatureStoreParameters params, String name) throws DataException {
2258

    
2259
        if (this.getFeatureTypes().size() != 1) {
2260
            throw new NotYetImplemented(
2261
                    "export whith more than one type not yet implemented");
2262
        }
2263
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2264
        FeatureStore target = null;
2265
        FeatureSet features = null;
2266
        DisposableIterator iterator = null;
2267
        try {
2268
            FeatureType type = this.getDefaultFeatureType();
2269
            if ((params.getDefaultFeatureType() == null)
2270
                    || (params.getDefaultFeatureType().size() == 0)) {
2271
                params.setDefaultFeatureType(type.getEditable());
2272

    
2273
            }
2274
            explorer.add(provider, params, true);
2275
            DataManager manager = DALLocator.getDataManager();
2276

    
2277
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2278
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2279

    
2280
            target = (FeatureStore) manager.openStore(provider, openParams);
2281
            FeatureType targetType = target.getDefaultFeatureType();
2282

    
2283
            target.edit(MODE_APPEND);
2284
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2285
            if (featureSelection.getSize() > 0) {
2286
                features = this.getFeatureSelection();
2287
            } else {
2288
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2289
                    FeatureQuery query = createFeatureQuery();
2290
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2291
                        query.getOrder().add(pkattr.getName(), true);
2292
                    }
2293
                    features = this.getFeatureSet(query);
2294
                } else {
2295
                    features = this.getFeatureSet();
2296
                }
2297
            }
2298
            iterator = features.fastIterator();
2299
            while (iterator.hasNext()) {
2300
                DefaultFeature feature = (DefaultFeature) iterator.next();
2301
                target.insert(target.createNewFeature(targetType, feature));
2302
            }
2303
            target.finishEditing();
2304
            target.dispose();
2305
        } catch (Exception e) {
2306
            throw new DataExportException(e, params.toString());
2307
        } finally {
2308
            dispose(iterator);
2309
            dispose(features);
2310
            dispose(target);
2311
        }
2312
    }
2313

    
2314
    @Override
2315
    public void copyTo(final FeatureStore target) {
2316
        boolean finishEditingAtEnd = false;
2317
        try {
2318
            if (!target.isEditing() && !target.isAppending()) {
2319
                finishEditingAtEnd = true;
2320
                target.edit(MODE_APPEND);
2321
            }
2322
            this.accept((Object obj) -> {
2323
                Feature f_src = (Feature) obj;
2324
                EditableFeature f_dst = target.createNewFeature(f_src);
2325
                target.insert(f_dst);
2326
            });
2327
            if (finishEditingAtEnd) {
2328
                target.finishEditing();
2329
            }
2330

    
2331
        } catch (Exception ex) {
2332
            try {
2333
                if (finishEditingAtEnd) {
2334
                    target.cancelEditing();
2335
                }
2336
            } catch (Exception ex1) {
2337
            }
2338
            throw new RuntimeException("Can't copy store.", ex);
2339
        }
2340

    
2341
    }
2342

    
2343
    //
2344
    // ====================================================================
2345
    // Obtencion de datos
2346
    // getDataCollection, getFeatureCollection
2347
    //
2348
    @Override
2349
    public DataSet getDataSet() throws DataException {
2350
        checkNotInAppendMode();
2351
        FeatureQuery query
2352
                = new DefaultFeatureQuery(this.getDefaultFeatureType());
2353
        return new DefaultFeatureSet(this, query);
2354
    }
2355

    
2356
    @Override
2357
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2358
        checkNotInAppendMode();
2359
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2360
    }
2361

    
2362
    @Override
2363
    public void getDataSet(Observer observer) throws DataException {
2364
        checkNotInAppendMode();
2365
        this.getFeatureSet(null, observer);
2366
    }
2367

    
2368
    @Override
2369
    public void getDataSet(DataQuery dataQuery, Observer observer)
2370
            throws DataException {
2371
        checkNotInAppendMode();
2372
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2373
    }
2374

    
2375
    @Override
2376
    public FeatureSet getFeatureSet() throws DataException {
2377
        return this.getFeatureSet((FeatureQuery) null);
2378
    }
2379

    
2380
    @Override
2381
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2382
            throws DataException {
2383
        checkNotInAppendMode();
2384
        if (featureQuery == null) {
2385
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2386
        }
2387
        return new DefaultFeatureSet(this, featureQuery);
2388
    }
2389

    
2390
    @Override
2391
    public FeatureSet getFeatureSet(String filter) throws DataException {
2392
        return this.getFeatureSet(filter, null, true);
2393
    }
2394

    
2395
    @Override
2396
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2397
        return this.getFeatureSet(filter, sortBy, true);
2398
    }
2399

    
2400
    @Override
2401
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2402
        return this.getFeatureSet(filter, null, true);
2403
    }
2404

    
2405
    @Override
2406
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2407
        return this.getFeatureSet(filter, sortBy, true);
2408
    }
2409

    
2410
    @Override
2411
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2412
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2413
        return this.getFeatureSet(query);
2414
    }
2415

    
2416
    @Override
2417
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2418
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2419
        return this.getFeatureSet(query);
2420
    }
2421

    
2422
    @Override
2423
    public List<Feature> getFeatures(String filter) {
2424
        return this.getFeatures(filter, null, true);
2425
    }
2426

    
2427
    @Override
2428
    public List<Feature> getFeatures(String filter, String sortBy) {
2429
        return this.getFeatures(filter, sortBy, true);
2430
    }
2431

    
2432
    @Override
2433
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc) {
2434
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2435
        return this.getFeatures(query, 0);
2436
    }
2437

    
2438
    @Override
2439
    public List<Feature> getFeatures(Expression filter) {
2440
        return this.getFeatures(filter, null, true);
2441
    }
2442

    
2443
    @Override
2444
    public List<Feature> getFeatures(Expression filter, String sortBy) {
2445
        return this.getFeatures(filter, sortBy, true);
2446
    }
2447

    
2448
    @Override
2449
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc) {
2450
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2451
        return this.getFeatures(query, 0);
2452
    }
2453

    
2454
    @Override
2455
    public List<Feature> getFeatures(FeatureQuery query) {
2456
        return this.getFeatures(query, 0);
2457
    }
2458

    
2459
    @Override
2460
    public List<Feature> getFeatures(FeatureQuery query, int pageSize) {
2461
        try {
2462
            if (pageSize <= 0) {
2463
                pageSize = 100;
2464
            }
2465
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2466
            return pager.asList();
2467
        } catch (BaseException ex) {
2468
            throw new RuntimeException("Can't create the list of features.", ex);
2469
        }
2470
    }
2471
        
2472
    @Override
2473
    public List<Feature> getFeatures() {
2474
        return this.getFeatures(null, 0);
2475
    }
2476

    
2477
    @Override
2478
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2479
        return this.getFeatures64(null, 0);
2480
    }
2481

    
2482
    @Override
2483
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2484
        return this.getFeatures64(filter, null, true);
2485
    }
2486

    
2487
    @Override
2488
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc) {
2489
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2490
        return this.getFeatures64(query, 0);
2491
    }
2492

    
2493
    @Override
2494
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize) {
2495
        try {
2496
            if (pageSize <= 0) {
2497
                pageSize = 100;
2498
            }
2499
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2500
            return pager;
2501
        } catch (BaseException ex) {
2502
            throw new RuntimeException("Can't create the list of features.", ex);
2503
        }
2504
    }
2505

    
2506
    @Override
2507
    public Feature first() throws DataException {
2508
        return this.findFirst((FeatureQuery) null);
2509
    }
2510

    
2511
    @Override
2512
    public Feature findFirst(String filter) throws DataException {
2513
        return this.findFirst(filter, (String) null, true);
2514
    }
2515

    
2516
    @Override
2517
    public Feature findFirst(String filter, String sortBy) throws DataException {
2518
        return this.findFirst(filter, sortBy, true);
2519
    }
2520

    
2521
    @Override
2522
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2523
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2524
        return findFirst(query);
2525
    }
2526

    
2527
    @Override
2528
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2529
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2530
        return findFirst(query);
2531
    }
2532

    
2533
    @Override
2534
    public Feature findFirst(Expression filter) throws DataException {
2535
        return this.findFirst(filter, (String) null, true);
2536
    }
2537

    
2538
    @Override
2539
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2540
        return this.findFirst(filter, sortBy, true);
2541
    }
2542

    
2543
    @Override
2544
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2545
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2546
        return findFirst(query);
2547
    }
2548

    
2549
    @Override
2550
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2551
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2552
        return findFirst(query);
2553
    }
2554

    
2555
    @Override
2556
    public Feature findFirst(FeatureQuery query) throws DataException {
2557
        if (query == null) {
2558
            query = this.createFeatureQuery();
2559
        } else {
2560
            query = query.getCopy();
2561
        }
2562
        query.setLimit(1);
2563
        final MutableObject<Feature> feature = new MutableObject<>();
2564
        try {
2565
            this.accept((Object obj) -> {
2566
                feature.setValue((Feature) obj);
2567
                throw new VisitCanceledException();
2568
            }, query);
2569
        } catch (VisitCanceledException ex) {
2570

    
2571
        } catch (DataException ex) {
2572
            throw ex;
2573
        } catch (Exception ex) {
2574
            throw new RuntimeException("", ex);
2575
        }
2576
        return feature.getValue();
2577
    }
2578

    
2579
    @Override
2580
    public void accept(Visitor visitor) throws BaseException {
2581
        this.accept(visitor, null);
2582
    }
2583

    
2584
    @Override
2585
    public void accept(Visitor visitor, DataQuery dataQuery)
2586
            throws BaseException {
2587
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2588
        try {
2589
            set.accept(visitor);
2590
        } finally {
2591
            set.dispose();
2592
        }
2593
    }
2594

    
2595
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2596
            throws DataException {
2597
        DefaultFeatureType fType
2598
                = (DefaultFeatureType) this.getFeatureType(featureQuery
2599
                        .getFeatureTypeId());
2600
        if (featureQuery.hasAttributeNames()
2601
                || featureQuery.hasConstantsAttributeNames()
2602
                || fType.hasRequiredFields()) {
2603
            if (featureQuery.hasGroupByColumns()) {
2604
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false);
2605
            } else {
2606
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2607
            }
2608
        }
2609
        return fType;
2610
    }
2611

    
2612
    @Override
2613
    public void getFeatureSet(Observer observer) throws DataException {
2614
        checkNotInAppendMode();
2615
        this.getFeatureSet(null, observer);
2616
    }
2617

    
2618
    @Override
2619
    public void getFeatureSet(FeatureQuery query, Observer observer)
2620
            throws DataException {
2621
        class LoadInBackGround implements Runnable {
2622

    
2623
            private final FeatureStore store;
2624
            private final FeatureQuery query;
2625
            private final Observer observer;
2626

    
2627
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2628
                    Observer observer) {
2629
                this.store = store;
2630
                this.query = query;
2631
                this.observer = observer;
2632
            }
2633

    
2634
            void notify(FeatureStoreNotification theNotification) {
2635
                observer.update(store, theNotification);
2636
            }
2637

    
2638
            @Override
2639
            public void run() {
2640
                FeatureSet set = null;
2641
                try {
2642
                    set = store.getFeatureSet(query);
2643
                    notify(new DefaultFeatureStoreNotification(store,
2644
                            FeatureStoreNotification.LOAD_FINISHED, set));
2645
                } catch (Exception e) {
2646
                    notify(new DefaultFeatureStoreNotification(store,
2647
                            FeatureStoreNotification.LOAD_FINISHED, e));
2648
                } finally {
2649
                    dispose(set);
2650
                }
2651
            }
2652
        }
2653

    
2654
        checkNotInAppendMode();
2655
        if (query == null) {
2656
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2657
        }
2658
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2659
        Thread thread = new Thread(task, "Load Feature Set in background");
2660
        thread.start();
2661
    }
2662

    
2663
    @Override
2664
    public Feature getFeatureByReference(FeatureReference reference)
2665
            throws DataException {
2666
        checkNotInAppendMode();
2667
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2668
        FeatureType featureType;
2669
        if (ref.getFeatureTypeId() == null) {
2670
            featureType = this.getDefaultFeatureType();
2671
        } else {
2672
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2673
        }
2674
        return this.getFeatureByReference(reference, featureType);
2675
    }
2676

    
2677
    @Override
2678
    public Feature getFeatureByReference(FeatureReference reference,
2679
            FeatureType featureType) throws DataException {
2680
        checkNotInAppendMode();
2681
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2682
        if (this.mode == MODE_FULLEDIT) {
2683
            Feature f = featureManager.get(reference, this, featureType);
2684
            if (f != null) {
2685
                return f;
2686
            }
2687
        }
2688

    
2689
        FeatureType sourceFeatureType = featureType;
2690
        if (!this.transforms.isEmpty()) {
2691
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2692
        }
2693
        // TODO comprobar que el id es de este store
2694

    
2695
        DefaultFeature feature
2696
                = new DefaultFeature(this,
2697
                        this.provider.getFeatureProviderByReference(
2698
                                (FeatureReferenceProviderServices) reference, sourceFeatureType));
2699

    
2700
        if (!this.transforms.isEmpty()) {
2701
            return this.transforms.applyTransform(feature, featureType);
2702
        }
2703
        return feature;
2704
    }
2705

    
2706
    //
2707
    // ====================================================================
2708
    // Gestion de features
2709
    //
2710
    private FeatureType fixFeatureType(DefaultFeatureType type)
2711
            throws DataException {
2712
        FeatureType original = this.getDefaultFeatureType();
2713

    
2714
        if ((type == null) || type.equals(original)) {
2715
            return original;
2716
        } else {
2717
            if (!type.isSubtypeOf(original)) {
2718
                Iterator iter = this.getFeatureTypes().iterator();
2719
                FeatureType tmpType;
2720
                boolean found = false;
2721
                while (iter.hasNext()) {
2722
                    tmpType = (FeatureType) iter.next();
2723
                    if (type.equals(tmpType)) {
2724
                        return type;
2725

    
2726
                    } else if (type.isSubtypeOf(tmpType)) {
2727
                        found = true;
2728
                        original = tmpType;
2729
                        break;
2730
                    }
2731

    
2732
                }
2733
                if (!found) {
2734
                    throw new IllegalFeatureTypeException(getName());
2735
                }
2736
            }
2737
        }
2738

    
2739
        // Checks that type has all fields of pk
2740
        // else add the missing attributes at the end.
2741
        if (!original.hasOID()) {
2742
            // Gets original pk attributes
2743
            DefaultEditableFeatureType edOriginal
2744
                    = (DefaultEditableFeatureType) original.getEditable();
2745
            FeatureAttributeDescriptor orgAttr;
2746
            Iterator edOriginalIter = edOriginal.iterator();
2747
            while (edOriginalIter.hasNext()) {
2748
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2749
                if (!orgAttr.isPrimaryKey()) {
2750
                    edOriginalIter.remove();
2751
                }
2752
            }
2753

    
2754
            // Checks if all pk attributes are in type
2755
            Iterator typeIterator;
2756
            edOriginalIter = edOriginal.iterator();
2757
            FeatureAttributeDescriptor attr;
2758
            while (edOriginalIter.hasNext()) {
2759
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2760
                typeIterator = type.iterator();
2761
                while (typeIterator.hasNext()) {
2762
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2763
                    if (attr.getName().equals(orgAttr.getName())) {
2764
                        edOriginalIter.remove();
2765
                        break;
2766
                    }
2767
                }
2768
            }
2769

    
2770
            // add missing pk attributes if any
2771
            if (edOriginal.size() > 0) {
2772
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2773
                DefaultEditableFeatureType edType
2774
                        = (DefaultEditableFeatureType) original.getEditable();
2775
                edType.clear();
2776
                edType.addAll(type);
2777
                edType.addAll(edOriginal);
2778
                if (!isEditable) {
2779
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2780
                }
2781
            }
2782

    
2783
        }
2784

    
2785
        return type;
2786
    }
2787

    
2788
    private void validateFeaturesAtFinishEditing() throws ValidateFeaturesException {
2789
        try {
2790
            checkInEditingMode();
2791
            FeatureType type = this.getDefaultFeatureTypeQuietly();
2792
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
2793

    
2794
            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS : 0;
2795
            checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
2796
            if (checks == 0) {
2797
                return;
2798
            }
2799

    
2800
            Iterator<EditableFeature> features = new ChainedIterator<>(
2801
                    featureManager.getInsertedFeatures(),
2802
                    featureManager.getUpdatedFeatures()
2803
            );
2804
            while (features.hasNext()) {
2805
                EditableFeature feature = features.next();
2806
                rules.validate(feature, checks);
2807
            }
2808
        } catch (Exception ex) {
2809
            throw new ValidateFeaturesException(this.getName(), ex);
2810
        }
2811
    }
2812

    
2813
    @Override
2814
    public FeatureType getDefaultFeatureType() throws DataException {
2815
        try {
2816

    
2817
            if (isEditing()) {
2818
                FeatureType auxFeatureType
2819
                        = featureTypeManager.getType(defaultFeatureType.getId());
2820
                if (auxFeatureType != null) {
2821
                    return avoidEditable(auxFeatureType);
2822
                }
2823
            }
2824
            FeatureType type = this.transforms.getDefaultFeatureType();
2825
            if (type != null) {
2826
                return avoidEditable(type);
2827
            }
2828

    
2829
            return avoidEditable(defaultFeatureType);
2830

    
2831
        } catch (Exception e) {
2832
            throw new GetFeatureTypeException(e, getName());
2833
        }
2834
    }
2835

    
2836
    @Override
2837
    public FeatureType getDefaultFeatureTypeQuietly() {
2838
        try {
2839
            return this.getDefaultFeatureType();
2840
        } catch (Exception ex) {
2841
            return null;
2842
        }
2843
    }
2844

    
2845
    private FeatureType avoidEditable(FeatureType ft) {
2846
        if (ft instanceof EditableFeatureType) {
2847
            return ((EditableFeatureType) ft).getNotEditableCopy();
2848
        } else {
2849
            return ft;
2850
        }
2851
    }
2852

    
2853
    @Override
2854
    public FeatureType getFeatureType(String featureTypeId)
2855
            throws DataException {
2856
        if (featureTypeId == null) {
2857
            return this.getDefaultFeatureType();
2858
        }
2859
        try {
2860
            if (isEditing()) {
2861
                FeatureType auxFeatureType
2862
                        = featureTypeManager.getType(featureTypeId);
2863
                if (auxFeatureType != null) {
2864
                    return auxFeatureType;
2865
                }
2866
            }
2867
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2868
            if (type != null) {
2869
                return type;
2870
            }
2871
            Iterator iter = this.featureTypes.iterator();
2872
            while (iter.hasNext()) {
2873
                type = (FeatureType) iter.next();
2874
                if (type.getId().equals(featureTypeId)) {
2875
                    return type;
2876
                }
2877
            }
2878
            return null;
2879
        } catch (Exception e) {
2880
            throw new GetFeatureTypeException(e, getName());
2881
        }
2882
    }
2883

    
2884
    public FeatureType getProviderDefaultFeatureType() {
2885
        return defaultFeatureType;
2886
    }
2887

    
2888
    @Override
2889
    public List getFeatureTypes() throws DataException {
2890
        try {
2891
            List types;
2892
            if (isEditing()) {
2893
                types = new ArrayList();
2894
                for (FeatureType type : featureTypes) {
2895
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2896
                    if (typeaux != null) {
2897
                        types.add(typeaux);
2898
                    } else {
2899
                        types.add(type);
2900
                    }
2901
                }
2902
                Iterator it = featureTypeManager.newsIterator();
2903
                while (it.hasNext()) {
2904
                    FeatureType type = (FeatureType) it.next();
2905
                    types.add(type);
2906
                }
2907
            } else {
2908
                types = this.transforms.getFeatureTypes();
2909
                if (types == null) {
2910
                    types = featureTypes;
2911
                }
2912
            }
2913
            return Collections.unmodifiableList(types);
2914
        } catch (Exception e) {
2915
            throw new GetFeatureTypeException(e, getName());
2916
        }
2917
    }
2918

    
2919
    public List getProviderFeatureTypes() throws DataException {
2920
        return Collections.unmodifiableList(this.featureTypes);
2921
    }
2922

    
2923
    @Override
2924
    public Feature createFeature(FeatureProvider data) throws DataException {
2925
        DefaultFeature feature = new DefaultFeature(this, data);
2926
        return feature;
2927
    }
2928

    
2929
    public Feature createFeature(FeatureProvider data, FeatureType type)
2930
            throws DataException {
2931
        // FIXME: falta por implementar
2932
        // Comprobar si es un subtipo del feature de data
2933
        // y construir un feature usando el subtipo.
2934
        // Probablemente requiera generar una copia del data.
2935
        throw new NotYetImplemented();
2936
    }
2937

    
2938
    @Override
2939
    public EditableFeature createNewFeature(FeatureType type,
2940
            Feature defaultValues) throws DataException {
2941
        try {
2942
            FeatureProvider data = createNewFeatureProvider(type);
2943
            DefaultEditableFeature feature
2944
                    = new DefaultEditableFeature(this, data);
2945
            feature.initializeValues(defaultValues);
2946
            data.setNew(true);
2947

    
2948
            return feature;
2949
        } catch (Exception e) {
2950
            throw new CreateFeatureException(e, getName());
2951
        }
2952
    }
2953

    
2954
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2955
            throws DataException {
2956
        type = this.fixFeatureType((DefaultFeatureType) type);
2957
        FeatureProvider data = this.provider.createFeatureProvider(type);
2958
        data.setNew(true);
2959
        if (type.hasOID() && (data.getOID() == null)) {
2960
            data.setOID(this.provider.createNewOID());
2961
        } else {
2962
            data.setOID(this.getTemporalOID());
2963
        }
2964
        return data;
2965

    
2966
    }
2967

    
2968
    @Override
2969
    public EditableFeature createNewFeature(FeatureType type,
2970
            boolean defaultValues) throws DataException {
2971
        try {
2972
            FeatureProvider data = createNewFeatureProvider(type);
2973
            DefaultEditableFeature feature
2974
                    = new DefaultEditableFeature(this, data);
2975
            if (defaultValues) {
2976
                feature.initializeValues();
2977
            }
2978
            return feature;
2979
        } catch (Exception e) {
2980
            throw new CreateFeatureException(e, getName());
2981
        }
2982
    }
2983

    
2984
    @Override
2985
    public EditableFeature createNewFeature(boolean defaultValues)
2986
            throws DataException {
2987
        return this.createNewFeature(this.getDefaultFeatureType(),
2988
                defaultValues);
2989
    }
2990

    
2991
    @Override
2992
    public EditableFeature createNewFeature() throws DataException {
2993
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2994
    }
2995

    
2996
    @Override
2997
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2998
        FeatureType ft = this.getDefaultFeatureType();
2999
        EditableFeature f = this.createNewFeature(ft, false);
3000
        f.copyFrom(defaultValues);
3001
        return f;
3002
    }
3003

    
3004
    @Override
3005
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
3006
        FeatureType ft = this.getDefaultFeatureType();
3007
        EditableFeature f = this.createNewFeature(ft, false);
3008
        f.copyFrom(defaultValues);
3009
        return f;
3010
    }
3011

    
3012
    @Override
3013
    public EditableFeatureType createFeatureType() {
3014
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
3015
        return ftype;
3016
    }
3017

    
3018
    @Override
3019
    public EditableFeatureType createFeatureType(String id) {
3020
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
3021
        return ftype;
3022
    }
3023

    
3024
    //
3025
    // ====================================================================
3026
    // Index related methods
3027
    //
3028
    @Override
3029
    public FeatureIndexes getIndexes() {
3030
        return this.indexes;
3031
    }
3032

    
3033
    @Override
3034
    public FeatureIndex createIndex(FeatureType featureType,
3035
            String attributeName, String indexName) throws DataException {
3036
        return createIndex(null, featureType, attributeName, indexName);
3037
    }
3038

    
3039
    @Override
3040
    public FeatureIndex createIndex(String indexTypeName,
3041
            FeatureType featureType, String attributeName, String indexName)
3042
            throws DataException {
3043

    
3044
        return createIndex(indexTypeName, featureType, attributeName,
3045
                indexName, false, null);
3046
    }
3047

    
3048
    @Override
3049
    public FeatureIndex createIndex(FeatureType featureType,
3050
            String attributeName, String indexName, Observer observer)
3051
            throws DataException {
3052
        return createIndex(null, featureType, attributeName, indexName,
3053
                observer);
3054
    }
3055

    
3056
    @Override
3057
    public FeatureIndex createIndex(String indexTypeName,
3058
            FeatureType featureType, String attributeName, String indexName,
3059
            final Observer observer) throws DataException {
3060

    
3061
        return createIndex(indexTypeName, featureType, attributeName,
3062
                indexName, true, observer);
3063
    }
3064

    
3065
    private FeatureIndex createIndex(String indexTypeName,
3066
            FeatureType featureType, String attributeName, String indexName,
3067
            boolean background, final Observer observer) throws DataException {
3068

    
3069
        checkNotInAppendMode();
3070
        FeatureIndexProviderServices index;
3071
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
3072
                featureType, indexName,
3073
                featureType.getAttributeDescriptor(attributeName));
3074

    
3075
        try {
3076
            index.fill(background, observer);
3077
        } catch (FeatureIndexException e) {
3078
            throw new InitializeException(index.getName(), e);
3079
        }
3080

    
3081
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
3082
        return index;
3083
    }
3084

    
3085
    //
3086
    // ====================================================================
3087
    // Transforms related methods
3088
    //
3089
    @Override
3090
    public FeatureStoreTransforms getTransforms() {
3091
        return this.transforms;
3092
    }
3093

    
3094
    @Override
3095
    public FeatureQuery createFeatureQuery() {
3096
        return new DefaultFeatureQuery(this.getName());
3097
    }
3098

    
3099
    @Override
3100
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
3101
        FeatureQuery query = null;
3102
        if (filter != null) {
3103
            query = this.createFeatureQuery();
3104
            query.setFilter(filter);
3105
        }
3106
        if (!StringUtils.isBlank(sortBy)) {
3107
            if (query == null) {
3108
                query = this.createFeatureQuery();
3109
            }
3110
            if (StringUtils.containsAny(sortBy, "(", ")")) {
3111
                throw new IllegalArgumentException("Incorrect sortBy expression");
3112
            }
3113
            String[] attrnames;
3114
            if (sortBy.contains(",")) {
3115
                attrnames = StringUtils.split(sortBy, ",");
3116
            } else {
3117
                attrnames = new String[]{sortBy};
3118
            }
3119
            for (String attrname : attrnames) {
3120
                attrname = attrname.trim();
3121
                if (attrname.startsWith("-")) {
3122
                    query.getOrder().add(attrname.substring(1).trim(), false);
3123
                } else if (attrname.endsWith("-")) {
3124
                    query.getOrder().add(attrname.substring(0, sortBy.length() - 1).trim(), false);
3125
                } else if (attrname.startsWith("+")) {
3126
                    query.getOrder().add(attrname.substring(1).trim(), true);
3127
                } else if (attrname.endsWith("-")) {
3128
                    query.getOrder().add(attrname.substring(0, sortBy.length() - 1).trim(), true);
3129
                } else {
3130
                    query.getOrder().add(attrname, asc);
3131
                }
3132
            }
3133
        }
3134
        if (query != null) {
3135
            query.retrievesAllAttributes();
3136
        }
3137
        return query;
3138
    }
3139

    
3140
    @Override
3141
    public FeatureQuery createFeatureQuery(String filter) {
3142
        return this.createFeatureQuery(
3143
                ExpressionUtils.createExpression(filter),
3144
                (String) null,
3145
                true
3146
        );
3147
    }
3148

    
3149
    @Override
3150
    public FeatureQuery createFeatureQuery(Expression filter) {
3151
        return this.createFeatureQuery(
3152
                filter,
3153
                (String) null,
3154
                true
3155
        );
3156
    }
3157

    
3158
    @Override
3159
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
3160
        if (StringUtils.isBlank(filter)) {
3161
            return this.createFeatureQuery(
3162
                    (Expression) null,
3163
                    sortBy,
3164
                    asc
3165
            );
3166
        } else {
3167
            return this.createFeatureQuery(
3168
                    ExpressionUtils.createExpression(filter),
3169
                    sortBy,
3170
                    asc
3171
            );
3172
        }
3173
    }
3174

    
3175
    @Override
3176
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
3177
        FeatureQuery query = null;
3178
        if (filter != null) {
3179
            query = this.createFeatureQuery();
3180
            query.setFilter(filter);
3181
        }
3182
        if (sortBy != null) {
3183
            if (query == null) {
3184
                query = this.createFeatureQuery();
3185
            }
3186
            query.getOrder().add(sortBy, asc);
3187
        }
3188

    
3189
        if (query != null) {
3190
            query.retrievesAllAttributes();
3191
        }
3192
        return query;
3193
    }
3194

    
3195
    @Override
3196
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3197
        if (StringUtils.isBlank(filter)) {
3198
            return this.createFeatureQuery(
3199
                    (Expression) null,
3200
                    sortBy,
3201
                    asc
3202
            );
3203
        } else {
3204
            return this.createFeatureQuery(
3205
                    ExpressionUtils.createExpression(filter),
3206
                    sortBy,
3207
                    asc
3208
            );
3209
        }
3210
    }
3211

    
3212
    @Override
3213
    public DataQuery createQuery() {
3214
        return createFeatureQuery();
3215
    }
3216

    
3217
    //
3218
    // ====================================================================
3219
    // UndoRedo related methods
3220
    //
3221
    @Override
3222
    public boolean canRedo() {
3223
        return commands.canRedo();
3224
    }
3225

    
3226
    @Override
3227
    public boolean canUndo() {
3228
        return commands.canUndo();
3229
    }
3230

    
3231
    @Override
3232
    public void redo(int num) throws RedoException {
3233
        for (int i = 0; i < num; i++) {
3234
            redo();
3235
        }
3236
    }
3237

    
3238
    @Override
3239
    public void undo(int num) throws UndoException {
3240
        for (int i = 0; i < num; i++) {
3241
            undo();
3242
        }
3243
    }
3244

    
3245
    //
3246
    // ====================================================================
3247
    // Metadata related methods
3248
    //
3249
    @Override
3250
    public Object getMetadataID() {
3251
        return this.provider.getSourceId();
3252
    }
3253

    
3254
    @Override
3255
    public void delegate(DynObject dynObject) {
3256
        this.metadata.delegate(dynObject);
3257
    }
3258

    
3259
    @Override
3260
    public DynClass getDynClass() {
3261
        return this.metadata.getDynClass();
3262
    }
3263

    
3264
    @Override
3265
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3266
        try {
3267
            if (this.transforms.hasDynValue(name)) {
3268
                return this.transforms.getDynValue(name);
3269
            }
3270
            if (this.metadata.hasDynValue(name)) {
3271
                return this.metadata.getDynValue(name);
3272
            }
3273
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3274
                return this.provider.getProviderName();
3275
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3276
                return this.provider.getSourceId();
3277
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3278
                try {
3279
                    return this.getDefaultFeatureType();
3280
                } catch (DataException e) {
3281
                    return null;
3282
                }
3283
            }
3284
            return this.metadata.getDynValue(name);
3285
        } catch (Exception ex) {
3286
            LOGGER.debug("Can't retrieve the value of '" + name + "' in store '" + this.getName() + "'.", ex);
3287
            return null;
3288
        }
3289
    }
3290

    
3291
    @Override
3292
    public boolean hasDynValue(String name) {
3293
        if (this.transforms.hasDynValue(name)) {
3294
            return true;
3295
        }
3296
        return this.metadata.hasDynValue(name);
3297
    }
3298

    
3299
    @Override
3300
    public boolean hasDynMethod(String name) {
3301
        return ((DynObject_v2) this.metadata).hasDynMethod(name);
3302
    }
3303

    
3304
    @Override
3305
    public void implement(DynClass dynClass) {
3306
        this.metadata.implement(dynClass);
3307
    }
3308

    
3309
    @Override
3310
    public Object invokeDynMethod(String name, Object[] args)
3311
            throws DynMethodException {
3312
        return this.metadata.invokeDynMethod(this, name, args);
3313
    }
3314

    
3315
    @Override
3316
    public Object invokeDynMethod(int code, Object[] args)
3317
            throws DynMethodException {
3318
        return this.metadata.invokeDynMethod(this, code, args);
3319
    }
3320

    
3321
    @Override
3322
    public void setDynValue(String name, Object value)
3323
            throws DynFieldNotFoundException {
3324
        if (this.transforms.hasDynValue(name)) {
3325
            this.transforms.setDynValue(name, value);
3326
            return;
3327
        }
3328
        this.metadata.setDynValue(name, value);
3329

    
3330
    }
3331

    
3332
    /*
3333
     * (non-Javadoc)
3334
     *
3335
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3336
     */
3337
    @Override
3338
    public Set getMetadataChildren() {
3339
        return this.metadataChildren;
3340
    }
3341

    
3342
    /*
3343
     * (non-Javadoc)
3344
     *
3345
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3346
     */
3347
    @Override
3348
    public String getMetadataName() {
3349
        return this.provider.getProviderName();
3350
    }
3351

    
3352
    public FeatureTypeManager getFeatureTypeManager() {
3353
        return this.featureTypeManager;
3354
    }
3355

    
3356
    @Override
3357
    public long getFeatureCount() throws DataException {
3358
        if (featureCount == null) {
3359
            featureCount = this.provider.getFeatureCount();
3360
        }
3361
        if (this.isEditing()) {
3362
            if (this.isAppending()) {
3363
                try {
3364
                    throw new IllegalStateException();
3365
                } catch (IllegalStateException e) {
3366
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND", e);
3367
                }
3368
                return -1;
3369
            } else {
3370
                return featureCount
3371
                        + this.featureManager.getDeltaSize();
3372
            }
3373
        }
3374
        return featureCount;
3375
    }
3376

    
3377
    private Long getTemporalOID() {
3378
        return this.temporalOid++;
3379
    }
3380

    
3381
    @Override
3382
    public FeatureType getProviderFeatureType(String featureTypeId) {
3383
        if (featureTypeId == null) {
3384
            return this.defaultFeatureType;
3385
        }
3386
        FeatureType type;
3387
        Iterator iter = this.featureTypes.iterator();
3388
        while (iter.hasNext()) {
3389
            type = (FeatureType) iter.next();
3390
            if (type.getId().equals(featureTypeId)) {
3391
                return type;
3392
            }
3393
        }
3394
        return null;
3395
    }
3396

    
3397
    @Override
3398
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3399
        return ((DefaultFeature) feature).getData();
3400
    }
3401

    
3402
    @Override
3403
    public DataStore getStore() {
3404
        return this;
3405
    }
3406

    
3407
    @Override
3408
    public FeatureStore getFeatureStore() {
3409
        return this;
3410
    }
3411

    
3412
    @Override
3413
    public void createCache(String name, DynObject parameters)
3414
            throws DataException {
3415
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3416
        if (cache == null) {
3417
            throw new CreateException("FeaureCacheProvider", null);
3418
        }
3419
        cache.apply(this, provider);
3420
        provider = cache;
3421

    
3422
        featureCount = null;
3423
    }
3424

    
3425
    @Override
3426
    public FeatureCache getCache() {
3427
        return cache;
3428
    }
3429

    
3430
    @Override
3431
    public void clear() {
3432
        if (metadata != null) {
3433
            metadata.clear();
3434
        }
3435
    }
3436

    
3437
    @Override
3438
    public String getName() {
3439
        if (this.provider != null) {
3440
            return this.provider.getName();
3441
        }
3442
        if (this.parameters instanceof HasAFile) {
3443
            return FilenameUtils.getName(((HasAFile) this.parameters).getFile().getName());
3444
        }
3445
        return "unknow";
3446
    }
3447

    
3448
    @Override
3449
    public String getFullName() {
3450
        try {
3451
            if (this.provider != null) {
3452
                return this.provider.getFullName();
3453
            }
3454
            if (this.parameters instanceof HasAFile) {
3455
                return (((HasAFile) this.parameters).getFile().getAbsolutePath());
3456
            }
3457
            return null;
3458
        } catch (Throwable th) {
3459
            return null;
3460
        }
3461
    }
3462

    
3463
    @Override
3464
    public String getProviderName() {
3465
        if (this.provider != null) {
3466
            return this.provider.getProviderName();
3467
        }
3468
        if (this.parameters != null) {
3469
            return this.parameters.getDataStoreName();
3470
        }
3471
        return null;
3472

    
3473
    }
3474

    
3475
    @Override
3476
    public boolean isKnownEnvelope() {
3477
        return this.provider.isKnownEnvelope();
3478
    }
3479

    
3480
    @Override
3481
    public boolean hasRetrievedFeaturesLimit() {
3482
        return this.provider.hasRetrievedFeaturesLimit();
3483
    }
3484

    
3485
    @Override
3486
    public int getRetrievedFeaturesLimit() {
3487
        return this.provider.getRetrievedFeaturesLimit();
3488
    }
3489

    
3490
    @Override
3491
    public Interval getInterval() {
3492
        if (this.timeSupport != null) {
3493
            return this.timeSupport.getInterval();
3494
        }
3495
        try {
3496
            FeatureType type = this.getDefaultFeatureType();
3497
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3498
            if (attr != null) {
3499
                Interval interval = attr.getInterval();
3500
                if (interval != null) {
3501
                    return interval;
3502
                }
3503
            }
3504
        } catch (DataException ex) {
3505
        }
3506
        return this.provider.getInterval();
3507
    }
3508

    
3509
    @Override
3510
    public Collection getTimes() {
3511
        if (this.timeSupport != null) {
3512
            return this.timeSupport.getTimes();
3513
        }
3514
        return this.provider.getTimes();
3515
    }
3516

    
3517
    @Override
3518
    public Collection getTimes(Interval interval) {
3519
        if (this.timeSupport != null) {
3520
            return this.timeSupport.getTimes(interval);
3521
        }
3522
        return this.provider.getTimes(interval);
3523
    }
3524

    
3525
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3526
        if (this.isEditing()) {
3527
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' while store is editing.");
3528
        }
3529
        if (!this.transforms.isEmpty()) {
3530
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' if has transforms.");
3531
        }
3532
        FeatureType ft = this.defaultFeatureType;
3533
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3534
        if (attr == null) {
3535
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "', this attribute don't exists.");
3536
        }
3537
        EditableFeatureType eft = ft.getEditable();
3538
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3539
        if (attr != null) {
3540
            if (!(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport)) {
3541
                throw new RuntimeException("Can't add time support, attribute '" + timeSupport.getAttributeName() + "'already exists.");
3542
            }
3543
            eft.remove(attr.getName());
3544
        }
3545
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3546
                timeSupport.getAttributeName(),
3547
                timeSupport.getDataType()
3548
        );
3549
        attrTime.setIsTime(true);
3550
        attrTime.setFeatureAttributeEmulator(timeSupport);
3551
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3552
        this.defaultFeatureType = eft.getNotEditableCopy();
3553

    
3554
        this.timeSupport = timeSupport;
3555
    }
3556

    
3557
    @Override
3558
    @SuppressWarnings("CloneDoesntCallSuperClone")
3559
    public Object clone() throws CloneNotSupportedException {
3560

    
3561
        DataStoreParameters dsp = getParameters();
3562

    
3563
        DefaultFeatureStore cloned_store = null;
3564

    
3565
        try {
3566
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3567
                    openStore(this.getProviderName(), dsp);
3568
            if (transforms != null) {
3569
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3570
                cloned_store.transforms.setStoreForClone(cloned_store);
3571
            }
3572
        } catch (Exception e) {
3573
            throw new CloneException(e);
3574
        }
3575
        return cloned_store;
3576

    
3577
    }
3578

    
3579
    @Override
3580
    public Feature getFeature(DynObject dynobject) {
3581
        if (dynobject instanceof DynObjectFeatureFacade) {
3582
            Feature f = ((DynObjectFeatureFacade) dynobject).getFeature();
3583
            return f;
3584
        }
3585
        return null;
3586
    }
3587

    
3588
    @Override
3589
    public Iterator iterator() {
3590
        FeatureSet fset = null;
3591
        try {
3592
            fset = this.getFeatureSet();
3593
            return fset.fastIterator();
3594
        } catch (DataException ex) {
3595
            throw new RuntimeException(ex);
3596
        } finally {
3597
            DisposeUtils.disposeQuietly(fset);
3598
        }
3599
    }
3600

    
3601
    @Override
3602
    public long size64() {
3603
        FeatureSet fset = null;
3604
        try {
3605
            fset = this.getFeatureSet();
3606
            return fset.getSize();
3607
        } catch (DataException ex) {
3608
            throw new RuntimeException(ex);
3609
        } finally {
3610
            DisposeUtils.disposeQuietly(fset);
3611
        }
3612
    }
3613

    
3614
    @Override
3615
    public ExpressionBuilder createExpressionBuilder() {
3616
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3617
        return builder;
3618
    }
3619

    
3620
    @Override
3621
    public ExpressionBuilder createExpression() {
3622
        return createExpressionBuilder();
3623
    }
3624

    
3625
    public FeatureSet features() throws DataException {
3626
        // This is to avoid jython to create a property with this name
3627
        // to access method getFeatures.
3628
        return this.getFeatureSet();
3629
    }
3630

    
3631
    @Override
3632
    public DataStoreProviderFactory getProviderFactory() {
3633
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3634
        return factory;
3635
    }
3636

    
3637
    @Override
3638
    public void useCache(String providerName, DynObject parameters) throws DataException {
3639
        throw new UnsupportedOperationException();
3640
    }
3641

    
3642
    @Override
3643
    public boolean isBroken() {
3644
        return this.state.isBroken();
3645
    }
3646

    
3647
    @Override
3648
    public Throwable getBreakingsCause() {
3649
        return this.state.getBreakingsCause();
3650
    }
3651

    
3652
    @Override
3653
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3654
        FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3655
        if (!factory.supportNumericOID()) {
3656
            return null;
3657
        }
3658
        SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3659
        return wrappedIndex;
3660
    }
3661

    
3662
    @Override
3663
    public FeatureReference getFeatureReference(String code) {
3664
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3665
        return featureReference;
3666
    }
3667

    
3668
    @Override
3669
    public long getPendingChangesCount() {
3670
        if (this.featureManager == null) {
3671
            return 0;
3672
        }
3673
        return this.featureManager.getPendingChangesCount();
3674
    }
3675

    
3676
    private ResourcesStorage resourcesStorage;
3677

    
3678
    @Override
3679
    public ResourcesStorage getResourcesStorage() {
3680
        if (this.resourcesStorage != null) {
3681
            DisposeUtils.bind(this.resourcesStorage);
3682
            return this.resourcesStorage;
3683
        }
3684
        ResourcesStorage theResourcesStorage;
3685
        try {
3686
            theResourcesStorage = this.provider.getResourcesStorage();
3687
            if (theResourcesStorage != null) {
3688
                this.resourcesStorage = theResourcesStorage;
3689
                DisposeUtils.bind(this.resourcesStorage);
3690
                return theResourcesStorage;
3691
            }
3692
        } catch (Throwable th) {
3693

    
3694
        }
3695
        try {
3696
            DataServerExplorer explorer = this.getExplorer();
3697
            if (explorer == null) {
3698
                return null;
3699
            }
3700
            theResourcesStorage = explorer.getResourcesStorage(this);
3701
            explorer.dispose();
3702
            this.resourcesStorage = theResourcesStorage;
3703
            DisposeUtils.bind(this.resourcesStorage);
3704
            return theResourcesStorage;
3705
        } catch (Exception ex) {
3706
            LOGGER.trace("Can't create resources storage", ex);
3707
            return null;
3708
        }
3709
    }
3710

    
3711
    @Override
3712
    public StoresRepository getStoresRepository() {
3713
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3714
        StoresRepository localRepository = this.provider.getStoresRepository();
3715
        if (localRepository == null) {
3716
            return mainRepository;
3717
        }
3718
        StoresRepository repository = new BaseStoresRepository(this.getName());
3719
        repository.addRepository(localRepository);
3720
        repository.addRepository(mainRepository);
3721
        return repository;
3722
    }
3723

    
3724
    @Override
3725
    public Feature getSampleFeature() {
3726
        if( sampleFeatureCache==null )  {
3727
            this.sampleFeatureCache = new CachedValue<Feature>(sample_feature_cache_timeout_ms) {
3728
                @Override
3729
                protected void reload() {
3730
                    Feature sampleFeature;
3731
                    long t1 = System.currentTimeMillis();
3732
                    try {                        
3733
                        FeatureSelection theSelection = getFeatureSelection();
3734
                        if (theSelection != null && !theSelection.isEmpty()) {
3735
                            sampleFeature = theSelection.first();
3736
                        } else {
3737
                            sampleFeature = first();
3738
                        }
3739
                        if (sampleFeature == null) {
3740
                            sampleFeature = createNewFeature();
3741
                        }
3742
                    } catch (DataException ex) {
3743
                        sampleFeature = null;
3744
                    }
3745
                    long t2 = System.currentTimeMillis();
3746
                    if( (t2 - t1)>5000 ) {
3747
                        // Mas de 5 seg es muy costoso, subimos mucho el tiempo de cache.
3748
                        this.setExpireTime(((60*60)*2)*1000); // 2h
3749
                    }
3750
                    this.setValue(sampleFeature);
3751
                }
3752
            };
3753
        }
3754
        return this.sampleFeatureCache.get();
3755
    }
3756

    
3757
    @Override
3758
    public boolean supportReferences() {
3759
        try {
3760
            return this.getDefaultFeatureType().supportReferences();
3761
        } catch (Exception ex) {
3762
            return false;
3763
        }
3764
    }
3765

    
3766
    private Boolean temporary = null;
3767
    
3768
    @Override
3769
    public boolean isTemporary() {
3770
        if(temporary != null) {
3771
            return this.temporary;
3772
        }
3773
        if (this.provider == null) {
3774
            return true;
3775
        }
3776
        return this.provider.isTemporary();
3777
    }
3778
    
3779
    @Override
3780
    public void setTemporary(Boolean temporary){
3781
        this.temporary = temporary;
3782
    }
3783

    
3784
    public FeatureType getOriginalFeatureType(FeatureType featureType) {
3785
        // FIXME this don't work for Store.fType.size() > 1
3786
        FeatureTypeManager manager = this.featureTypeManager;
3787
        if (manager == null) {
3788
            return null;
3789
        }
3790
        FeatureType originalFeatureType = manager.getOriginalFeatureType();
3791
        if (originalFeatureType == null) {
3792
            return null;
3793
        }
3794
        return originalFeatureType.getCopy();
3795
    }
3796

    
3797
    @Override
3798
    public Object getProperty(String name) {
3799
        if (this.propertiesSupportHelper == null) {
3800
            return null;
3801
        }
3802
        return this.propertiesSupportHelper.getProperty(name);
3803
    }
3804

    
3805
    @Override
3806
    public void setProperty(String name, Object value) {
3807
        if (this.propertiesSupportHelper == null) {
3808
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3809
        }
3810
        this.propertiesSupportHelper.setProperty(name, value);
3811
    }
3812

    
3813
    @Override
3814
    public Map<String, Object> getProperties() {
3815
        if (this.propertiesSupportHelper == null) {
3816
            return Collections.EMPTY_MAP;
3817
        }
3818
        return this.propertiesSupportHelper.getProperties();
3819
    }
3820

    
3821
    @Override
3822
    public Feature getOriginalFeature(FeatureReference id) {
3823
        if (this.featureManager == null) {
3824
            return null;
3825
        }
3826
        return featureManager.getOriginal(id);
3827
    }
3828

    
3829
    @Override
3830
    public Feature getOriginalFeature(Feature feature) {
3831
        if (feature == null) {
3832
            return null;
3833
        }
3834
        return getOriginalFeature(feature.getReference());
3835
    }
3836

    
3837
    @Override
3838
    public boolean isFeatureModified(FeatureReference id) {
3839
        if (this.featureManager == null) {
3840
            return false;
3841
        }
3842
        return featureManager.isFeatureModified(id);
3843
    }
3844

    
3845
    @Override
3846
    public boolean isFeatureModified(Feature feature) {
3847
        if (feature == null) {
3848
            return false;
3849
        }
3850
        return isFeatureModified(feature.getReference());
3851
    }
3852

    
3853
    @Override
3854
    public void setTransaction(DataTransaction transaction) {
3855
        if( this.transaction!=null ) {
3856
            this.transaction.deleteObserver(transactionObserver);
3857
        }
3858
        this.transaction = transaction;
3859
        if (transaction instanceof DataTransactionServices) {
3860
            this.provider.setTransaction((DataTransactionServices) transaction);
3861
        }
3862
        if( transaction!=null ) {
3863
            transaction.addObserver(transactionObserver);
3864
        }
3865
    }
3866

    
3867
    @Override
3868
    public DataTransaction getTransaction() {
3869
        return transaction;
3870
    }
3871

    
3872
    @Override
3873
    public String toString() {
3874
        try {
3875
            return String.format("%s %x %s", this.getClass().getSimpleName(), this.hashCode(), this.getFullName());
3876
        } catch (Exception e) {
3877
            return super.toString();
3878
        }
3879
    }
3880

    
3881
    public String createUniqueID() {
3882
        UUID x = UUID.randomUUID();
3883
        String s = x.toString();
3884
        return s;
3885
    }
3886

    
3887
    @Override
3888
    public List<FeatureReference> getEditedFeatures() {
3889
        if( this.featureManager == null ) {
3890
            return Collections.EMPTY_LIST;
3891
        }
3892
        List<FeatureReference> references = this.featureManager.getAddedAndUpdatedFeatures();
3893
        if( references==null ) {
3894
            return Collections.EMPTY_LIST;
3895
        }
3896
        return references;
3897
    }
3898
    
3899
    public List<FeatureReference> getEditedFeaturesNotValidated() {
3900

    
3901
        try {
3902
            if (this.featureManager == null) {
3903
                return Collections.EMPTY_LIST;
3904
            }
3905
            
3906
            FeatureType type = this.getDefaultFeatureTypeQuietly();
3907
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
3908
            
3909
//            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS | CHECK_BASIC : 0;
3910
            int checks = CHECK_REQUIREDS | CHECK_BASIC;
3911
            if(type.isCheckFeaturesAtFinishEditing()){
3912
                checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
3913
            }
3914
            if (checks == 0) {
3915
                return Collections.EMPTY_LIST;
3916
            }
3917
            List<FeatureReference> references = this.featureManager
3918
                    .getAddedAndUpdatedFeaturesNotValidated(rules, checks);
3919
            if (references == null) {
3920
                return Collections.EMPTY_LIST;
3921
            }
3922
            return references;
3923
        } catch (DataException ex) {
3924
            return null;
3925
        }
3926

    
3927
    }
3928

    
3929
    @Override
3930
    public Iterator<Feature> getFeaturesIterator(Iterator<FeatureReference> references) {
3931
        return new FeatureReferenceIteratorToFeatureIterator(this, references);
3932
    }
3933

    
3934
    @Override
3935
    public Iterable<Feature> getFeaturesIterable(Iterator<FeatureReference> references) {
3936
        return () -> new FeatureReferenceIteratorToFeatureIterator(this, references);
3937
    }
3938

    
3939
    @Override
3940
    public boolean isFeatureSelectionAvailable() {
3941
        try {
3942
            FeatureType type = this.getDefaultFeatureType();
3943
            return type.supportReferences();
3944
        } catch (DataException ex) {
3945
            return false;
3946
        }
3947
    }
3948
}