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

History | View | Annotate | Download (141 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 int lastMode = MODE_QUERY;
225
    
226
    private long versionOfUpdate = 0;
227
    private boolean hasStrongChanges = true;
228

    
229
    private DefaultDataManager dataManager = null;
230

    
231
    private FeatureStoreProvider provider = null;
232

    
233
    private DefaultFeatureIndexes indexes;
234

    
235
    private DefaultFeatureStoreTransforms transforms;
236

    
237
    /*friend*/ DelegatedDynObject metadata;
238

    
239
    private Set metadataChildren;
240

    
241
    private Long featureCount = null;
242

    
243
    private long temporalOid = 0;
244

    
245
    private FeatureCacheProvider cache;
246

    
247
    private final StateInformation state;
248

    
249
    private FeatureStoreTimeSupport timeSupport;
250

    
251
    private PropertiesSupportHelper propertiesSupportHelper;
252
    private DataTransaction transaction;
253

    
254
    private String editingSessionCode;
255
    private String lastEditingSessionCode;
256
    
257
    private CachedValue<Feature> sampleFeatureCache;
258
    
259
    private final Observer transactionObserver;
260

    
261
    private class StateInformation extends HashMap<Object, Object> {
262

    
263
        private static final long serialVersionUID = 4109026189635185666L;
264

    
265
        private boolean broken;
266
        private Throwable breakingsCause;
267

    
268
        @SuppressWarnings("OverridableMethodCallInConstructor")
269
        public StateInformation() {
270
            this.clear();
271
        }
272

    
273
        @Override
274
        public void clear() {
275
            this.broken = false;
276
            this.breakingsCause = null;
277
            super.clear();
278
        }
279

    
280
        public boolean isBroken() {
281
            return this.broken;
282
        }
283

    
284
        public void broken() {
285
            this.broken = true;
286
        }
287

    
288
        public Throwable getBreakingsCause() {
289
            return this.breakingsCause;
290
        }
291

    
292
        public void setBreakingsCause(Throwable cause) {
293
            if (this.breakingsCause == null) {
294
                this.breakingsCause = cause;
295
            }
296
            this.broken = true;
297
        }
298
    }
299

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

    
324
    @Override
325
    protected DataManager getDataManager() {
326
        return this.dataManager;
327
    }
328

    
329
    @Override
330
    public void intialize(DataManager dataManager,
331
            DataStoreParameters parameters) throws InitializeException {
332

    
333
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
334

    
335
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
336
                FeatureStore.METADATA_DEFINITION_NAME,
337
                MetadataManager.METADATA_NAMESPACE
338
        );
339

    
340
        this.dataManager = (DefaultDataManager) dataManager;
341

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

    
350
    }
351

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

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

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

    
391
    @Override
392
    public int getMode() {
393
        return this.mode;
394
    }
395

    
396
    @Override
397
    public DataManager getManager() {
398
        return this.dataManager;
399
    }
400

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

    
410
    @Override
411
    public FeatureStoreProvider getProvider() {
412
        return this.provider;
413
    }
414

    
415
    public FeatureManager getFeatureManager() {
416
        return this.featureManager;
417
    }
418

    
419
    @Override
420
    public void setFeatureTypes(List types, FeatureType defaultType) {
421
        this.featureTypes = types;
422
        this.defaultFeatureType = defaultType;
423
    }
424

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

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

    
459
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
460
    }
461

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

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

    
507
        if (this.featureTypeManager != null) {
508
            this.featureTypeManager.dispose();
509
            this.featureTypeManager = null;
510
        }
511

    
512
        this.featureManager = null;
513
        this.spatialManager = null;
514

    
515
        this.parameters = null;
516
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
517
        if (delegateObservable != null) {
518
            this.delegateObservable.deleteObservers();
519
            this.delegateObservable = null;
520
        }
521
        DisposeUtils.disposeQuietly(this.resourcesStorage);
522
        if( this.transaction!=null ) {
523
            this.transaction.deleteObserver(transactionObserver);
524
            this.transaction = null;
525
        }
526
    }
527

    
528
    @Override
529
    public boolean allowWrite() {
530
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
531
        if (!identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION, this.getParameters(), this.getName())) {
532
            return false;
533
        }
534
        return this.provider.allowWrite();
535
    }
536

    
537
    @Override
538
    public boolean canWriteGeometry(int geometryType) throws DataException {
539
        return this.provider.canWriteGeometry(geometryType, 0);
540
    }
541

    
542
    @Override
543
    public DataServerExplorer getExplorer() throws ReadException,
544
            ValidateDataParametersException {
545
        if (this.state.isBroken()) {
546
            try {
547
                return this.provider.getExplorer();
548
            } catch (Throwable th) {
549
                return null;
550
            }
551
        } else {
552
            return this.provider.getExplorer();
553
        }
554
    }
555

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

    
626
    /**
627
     * @throws org.gvsig.fmap.dal.exception.DataException
628
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
629
     */
630
    @Override
631
    public IProjection getSRSDefaultGeometry() throws DataException {
632
        return this.getDefaultFeatureType().getDefaultSRS();
633
    }
634

    
635
    @Override
636
    public FeatureSelection createDefaultFeatureSelection()
637
            throws DataException {
638
        return new DefaultFeatureSelection(this);
639
    }
640

    
641
    @Override
642
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
643
            throws DataException {
644
        if (type.hasOID()) {
645
            return new DefaultFeatureProvider(type,
646
                    this.provider.createNewOID());
647
        }
648
        return new DefaultFeatureProvider(type);
649
    }
650

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

    
686
        }
687

    
688
        if (evaluatedAttr.isEmpty()) {
689
            evaluatedAttr = null;
690
        }
691

    
692
        state.set("evaluatedAttributes", evaluatedAttr);
693
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
694

    
695
    }
696

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

    
736
    private void load(StateInformation state) {
737
        this.featureTypes = new ArrayList();
738
        this.defaultFeatureType = null;
739
        this.featureCount = null;
740

    
741
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
742
        try {
743
            intialize(dataManager, params);
744
        } catch (Throwable th) {
745
            state.setBreakingsCause(th);
746
        }
747

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

    
764
        try {
765
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
766
            this.transforms.setFeatureStore(this);
767
            for (FeatureStoreTransform transform : this.transforms) {
768
                try {
769
                    transform.setUp();
770
                } catch (Throwable th) {
771
                    state.setBreakingsCause(th);
772
                }
773
            }
774
        } catch (Throwable th) {
775
            state.setBreakingsCause(th);
776
        }
777

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

    
809
                }
810

    
811
            }
812
        } catch (Throwable th) {
813
            state.setBreakingsCause(th);
814
        }
815

    
816
        try {
817
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
818
            FeatureType ftype;
819

    
820
            if (defaultFeatureType == null
821
                    || defaultFeatureType.getId() == null
822
                    || !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
823

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

    
843
        LOGGER.debug("load() broken:{}, {}, {}.",
844
                new Object[]{state.isBroken(), this.getProviderName(), params}
845
        );
846
    }
847

    
848
    public DataStoreProviderServices getStoreProviderServices() {
849
        return this;
850
    }
851

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

    
874
    private static void registerPersistenceDefinition() {
875
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
876
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
877
            DynStruct definition
878
                    = manager.addDefinition(DefaultFeatureStore.class,
879
                            PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
880
                            + " Persistent definition", null, null);
881
            definition.addDynFieldString("dataStoreName").setMandatory(true)
882
                    .setPersistent(true);
883

    
884
            definition.addDynFieldObject("parameters")
885
                    .setClassOfValue(DynObject.class).setMandatory(true)
886
                    .setPersistent(true);
887

    
888
            definition.addDynFieldObject("selection")
889
                    .setClassOfValue(FeatureSelection.class).setMandatory(false)
890
                    .setPersistent(true);
891

    
892
            definition.addDynFieldObject("transforms")
893
                    .setClassOfValue(DefaultFeatureStoreTransforms.class)
894
                    .setMandatory(true).setPersistent(true);
895

    
896
            definition.addDynFieldMap("evaluatedAttributes")
897
                    .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
898
                    .setMandatory(false).setPersistent(true);
899

    
900
            definition.addDynFieldString("defaultFeatureTypeId")
901
                    .setMandatory(true).setPersistent(true);
902
        }
903
    }
904

    
905
    private static void registerMetadataDefinition() throws MetadataException {
906
        MetadataManager manager = MetadataLocator.getMetadataManager();
907
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
908
            DynStruct metadataDefinition
909
                    = manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
910
            metadataDefinition.extend(manager
911
                    .getDefinition(DataStore.METADATA_DEFINITION_NAME));
912
        }
913
    }
914

    
915
    //
916
    // ====================================================================
917
    // Gestion de la seleccion
918
    //
919
    @Override
920
    public void setSelection(DataSet selection) throws DataException {
921
        this.setSelection((FeatureSet) selection);
922
    }
923

    
924
    @Override
925
    public DataSet createSelection() throws DataException {
926
        return createFeatureSelection();
927
    }
928

    
929
    @Override
930
    public DataSet getSelection() throws DataException {
931
        return this.getFeatureSelection();
932
    }
933

    
934
    @Override
935
    public void setSelection(FeatureSet selection) throws DataException {
936
        setSelection(selection, true);
937
    }
938

    
939
    public void setSelection(FeatureSet selection, boolean undoable)
940
            throws DataException {
941
        if (selection == null) {
942
            if (undoable) {
943
                throw new SelectionNotAllowedException(getName());
944
            }
945

    
946
        } else {
947
            if (selection.equals(this.selection)) {
948
                return;
949
            }
950
            if (!selection.isFromStore(this)) {
951
                throw new SelectionNotAllowedException(getName());
952
            }
953
        }
954

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

    
996
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
997
    }
998

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

    
1019
    @Override
1020
    public FeatureSelection createLargeFeatureSelection() throws DataException {
1021
        return new LargeFeatureSelection(this);
1022

    
1023
    }
1024

    
1025
    @Override
1026
    public FeatureSelection createMemoryFeatureSelection() throws DataException {
1027
        return this.provider.createFeatureSelection();
1028
    }
1029

    
1030
    @Override
1031
    public FeatureSelection getFeatureSelection() throws DataException {
1032
        if (selection == null) {
1033
            this.selection = createFeatureSelection();
1034
            this.selection.addObserver(this);
1035
        }
1036
        return selection;
1037
    }
1038

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

    
1063
    @Override
1064
    public FeatureStoreNotification notifyChange(String notification) {
1065
        return notifyChange(
1066
                new DefaultFeatureStoreNotification(
1067
                        this, notification, 
1068
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1069
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode
1070
                )
1071
        );
1072
    }
1073

    
1074
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode) {
1075
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode));
1076
    }
1077

    
1078
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode, int editMode) {
1079
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode, editMode));
1080
    }
1081

    
1082
    public FeatureStoreNotification notifyChange(String notification,
1083
//            String editingSessionCode,
1084
            Iterator<FeatureReference> deleteds,
1085
            Iterator<EditableFeature> inserteds,
1086
            Iterator<EditableFeature> updateds,
1087
            Iterator<FeatureTypeChanged> featureTypesChanged,
1088
            boolean isSelectionCompromised) {
1089
        return notifyChange(
1090
                new DefaultFeatureStoreNotification(
1091
                        this, notification, 
1092
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1093
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1094
                        deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised
1095
                )
1096
        );
1097
    }
1098

    
1099
    @Override
1100
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
1101
        Feature f = null;
1102
        if (data != null) {
1103
            try {
1104
                f = createFeature(data);
1105
            } catch (Throwable ex) {
1106
                LOGGER.warn("Problems creating a feature to notifying changes in the store '" + this.getName() + " (" + notification + ").", ex);
1107
            }
1108
        }
1109
        return notifyChange(notification, f);
1110
    }
1111

    
1112
    public FeatureStoreNotification notifyChange(String notification, Feature feature) {
1113
        return notifyChange(
1114
                new DefaultFeatureStoreNotification(
1115
                        this, notification, 
1116
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1117
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1118
                        feature
1119
                )
1120
        );
1121
    }
1122

    
1123
    public FeatureStoreNotification notifyChange(String notification, Expression expression) {
1124
        return notifyChange(
1125
                new DefaultFeatureStoreNotification(
1126
                        this, notification, 
1127
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1128
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1129
                        expression
1130
                )
1131
        );
1132
    }
1133

    
1134
    public FeatureStoreNotification notifyChange(String notification, Command command) {
1135
        return notifyChange(
1136
                new DefaultFeatureStoreNotification(
1137
                        this, notification, 
1138
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1139
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1140
                        command
1141
                )
1142
        );
1143
    }
1144

    
1145
    public FeatureStoreNotification notifyChange(String notification, EditableFeatureType type) {
1146
        return notifyChange(
1147
                new DefaultFeatureStoreNotification(
1148
                        this, notification, 
1149
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1150
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1151
                        type
1152
                )
1153
        );
1154
    }
1155

    
1156
    @Override
1157
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
1158
        return notifyChange(
1159
                new DefaultFeatureStoreNotification(
1160
                        this, DataStoreNotification.RESOURCE_CHANGED
1161
                )
1162
        );
1163
    }
1164

    
1165
    //
1166
    // ====================================================================
1167
    // Gestion de bloqueos
1168
    //
1169
    @Override
1170
    public boolean isLocksSupported() {
1171
        return this.provider.isLocksSupported();
1172
    }
1173

    
1174
    @Override
1175
    public FeatureLocks getLocks() throws DataException {
1176
        if (!this.provider.isLocksSupported()) {
1177
            LOGGER.warn("Locks not supported");
1178
            return null;
1179
        }
1180
        if (locks == null) {
1181
            this.locks = this.provider.createFeatureLocks();
1182
        }
1183
        return locks;
1184
    }
1185

    
1186
    //
1187
    // ====================================================================
1188
    // Interface Observable
1189
    //
1190
    @Override
1191
    public void disableNotifications() {
1192
        this.delegateObservable.disableNotifications();
1193

    
1194
    }
1195

    
1196
    @Override
1197
    public void enableNotifications() {
1198
        this.delegateObservable.enableNotifications();
1199
    }
1200

    
1201
    @Override
1202
    public void beginComplexNotification() {
1203
        this.delegateObservable.beginComplexNotification();
1204

    
1205
    }
1206

    
1207
    @Override
1208
    public void endComplexNotification() {
1209
        this.delegateObservable.endComplexNotification();
1210

    
1211
    }
1212

    
1213
    @Override
1214
    public void addObserver(Observer observer) {
1215
        if (delegateObservable != null) {
1216
            this.delegateObservable.addObserver(observer);
1217
        }
1218
    }
1219

    
1220
    @Override
1221
    public void deleteObserver(Observer observer) {
1222
        if (delegateObservable != null) {
1223
            this.delegateObservable.deleteObserver(observer);
1224
        }
1225
    }
1226

    
1227
    @Override
1228
    public void deleteObservers() {
1229
        this.delegateObservable.deleteObservers();
1230

    
1231
    }
1232

    
1233
    //
1234
    // ====================================================================
1235
    // Interface Observer
1236
    //
1237
    // Usado para observar:
1238
    // - su seleccion
1239
    // - sus bloqueos
1240
    // - sus recursos
1241
    //
1242
    @Override
1243
    public void update(Observable observable, Object notification) {
1244
        if (observable instanceof FeatureSet) {
1245
            if (observable == this.selection) {
1246
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1247
            } else if (observable == this.locks) {
1248
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1249
            }
1250

    
1251
        } else if (observable instanceof FeatureStoreProvider) {
1252
            if (observable == this.provider) {
1253

    
1254
            }
1255
        } else if (observable instanceof FeatureReferenceSelection) {
1256
            if (notification instanceof String) {
1257
                this.notifyChange((String) notification);
1258
            }
1259
        }
1260
    }
1261

    
1262
    //
1263
    // ====================================================================
1264
    // Edicion
1265
    //
1266
    private void newVersionOfUpdate() {
1267
        this.versionOfUpdate++;
1268
    }
1269

    
1270
    private long currentVersionOfUpdate() {
1271
        return this.versionOfUpdate;
1272
    }
1273

    
1274
    private void checkInEditingMode() throws NeedEditingModeException {
1275
        if (mode != MODE_FULLEDIT) {
1276
            throw new NeedEditingModeException(this.getName());
1277
        }
1278
    }
1279

    
1280
    private void checkNotInAppendMode() throws IllegalStateException {
1281
        if (mode == MODE_APPEND) {
1282
            throw new IllegalStateException("Error: store "
1283
                    + this.getFullName() + " is in append mode");
1284
        }
1285
    }
1286

    
1287
    private void checkIsOwnFeature(Feature feature)
1288
            throws IllegalFeatureException {
1289
        if (((DefaultFeature) feature).getStore() != this) {
1290
            throw new IllegalFeatureException(this.getName());
1291
        }
1292
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1293
        // fixFeatureType((DefaultFeatureType) feature.getType());
1294
    }
1295

    
1296
    private void exitEditingMode() {
1297
        if (commands != null) {
1298
            try {
1299
                commands.clear();
1300
            } catch (Exception ex) {
1301
                LOGGER.trace("Can't clear commands", ex);
1302
            }
1303
            commands = null;
1304
        }
1305

    
1306
        if (featureTypeManager != null) {
1307
            DisposeUtils.disposeQuietly(featureTypeManager);
1308
            featureTypeManager = null;
1309

    
1310
        }
1311

    
1312
        // TODO implementar un dispose para estos dos
1313
        featureManager = null;
1314
        spatialManager = null;
1315

    
1316
        featureCount = null;
1317

    
1318
        this.lastMode = this.mode;
1319
        mode = MODE_QUERY;
1320
        hasStrongChanges = true; // Lo deja a true por si las moscas
1321

    
1322
        this.lastEditingSessionCode = this.editingSessionCode;
1323
        this.editingSessionCode = null;
1324
    }
1325

    
1326
    @Override
1327
    synchronized public void edit() throws DataException {
1328
        edit(MODE_FULLEDIT);
1329
    }
1330

    
1331
    @Override
1332
    synchronized public void edit(int mode) throws DataException {
1333
        LOGGER.debug("Starting editing in mode: {}", mode);
1334
        String newSessionCode = this.createUniqueID();
1335
        try {
1336
            if (this.mode != MODE_QUERY) {
1337
                throw new AlreadyEditingException(this.getName());
1338
            }
1339
            if (!this.provider.supportsAppendMode()) {
1340
                mode = MODE_FULLEDIT;
1341
            }
1342
            switch (mode) {
1343
                case MODE_QUERY:
1344
                    throw new IllegalStateException(this.getName());
1345

    
1346
                case MODE_FULLEDIT:
1347
                    if (!this.transforms.isEmpty()) {
1348
                        throw new IllegalStateException(this.getName());
1349
                    }
1350
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1351
                            newSessionCode, mode).isCanceled()) {
1352
                        return;
1353
                    }
1354
                    this.editingSessionCode = newSessionCode;
1355
                    invalidateIndexes();
1356
                    featureManager = new FeatureManager(this);
1357
                    featureTypeManager = new FeatureTypeManager(this);
1358
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
1359

    
1360
                    commands = new DefaultFeatureCommandsStack(
1361
                            this, featureManager,
1362
                            spatialManager, featureTypeManager);
1363
                    this.mode = MODE_FULLEDIT;
1364
                    hasStrongChanges = false;
1365
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING, newSessionCode, this.mode);
1366
                    break;
1367

    
1368
                case MODE_APPEND:
1369
                    if (!this.transforms.isEmpty()) {
1370
                        throw new IllegalStateException(this.getName());
1371
                    }
1372
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1373
                            newSessionCode, mode).isCanceled()) {
1374
                        return;
1375
                    }
1376
                    this.editingSessionCode = newSessionCode;
1377
                    invalidateIndexes();
1378
                    this.provider.beginAppend();
1379
                    this.mode = MODE_APPEND;
1380
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1381
                            newSessionCode, this.mode);
1382
                    break;
1383
                case MODE_PASS_THROUGH:
1384
                    if (!this.provider.supportsPassThroughMode()) {
1385
                        throw new IllegalStateException(this.getName());
1386
                    }
1387
                    if (!this.transforms.isEmpty()) {
1388
                        throw new IllegalStateException(this.getName());
1389
                    }
1390
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1391
                            newSessionCode, mode).isCanceled()) {
1392
                        return;
1393
                    }
1394
                    this.editingSessionCode = newSessionCode;
1395
                    invalidateIndexes();
1396
                    this.mode = MODE_PASS_THROUGH;
1397
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1398
                            newSessionCode, this.mode);
1399
                    break;
1400

    
1401
            }
1402
        } catch (Exception e) {
1403
            try {
1404
                if (this.mode != MODE_QUERY) {
1405
                    exitEditingMode();
1406
                }
1407
                notifyChange(FeatureStoreNotification.FAILED_STARTEDITING,
1408
                        newSessionCode, mode);
1409
            } catch (Throwable th) {
1410
                LOGGER.warn("Can't cleanup after error in start editing.", th);
1411
            }
1412
            throw new StoreEditException(e, this.getName());
1413
        }
1414
    }
1415

    
1416
    private void invalidateIndexes() {
1417
        setIndexesValidStatus(false);
1418
    }
1419

    
1420
    private void setIndexesValidStatus(boolean valid) {
1421
        FeatureIndexes theIndexes = getIndexes();
1422
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1423
                ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1424
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1425
            FeatureIndex index = (FeatureIndex) iterator.next();
1426
            if (index instanceof FeatureIndexProviderServices) {
1427
                FeatureIndexProviderServices indexServices
1428
                        = (FeatureIndexProviderServices) index;
1429
                indexServices.setValid(valid);
1430
            }
1431
        }
1432
    }
1433

    
1434
    private void updateIndexes() throws FeatureIndexException {
1435
        FeatureIndexes theIndexes = getIndexes();
1436
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1437
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1438
            FeatureIndex index = (FeatureIndex) iterator.next();
1439
            if (index instanceof FeatureIndexProviderServices) {
1440
                FeatureIndexProviderServices indexServices
1441
                        = (FeatureIndexProviderServices) index;
1442
                indexServices.fill(true, null);
1443
            }
1444
        }
1445
    }
1446

    
1447
    private void waitForIndexes() {
1448
        FeatureIndexes theIndexes = getIndexes();
1449
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1450
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1451
            FeatureIndex index = (FeatureIndex) iterator.next();
1452
            if (index instanceof FeatureIndexProviderServices) {
1453
                FeatureIndexProviderServices indexServices
1454
                        = (FeatureIndexProviderServices) index;
1455
                indexServices.waitForIndex();
1456
            }
1457
        }
1458
    }
1459

    
1460
    private void disposeIndexes() {
1461
        FeatureIndexes theIndexes = getIndexes();
1462
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1463
        if (theIndexes == null) {
1464
            return;
1465
        }
1466
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1467
            FeatureIndex index = (FeatureIndex) iterator.next();
1468
            if (index instanceof FeatureIndexProviderServices) {
1469
                FeatureIndexProviderServices indexServices
1470
                        = (FeatureIndexProviderServices) index;
1471
                indexServices.dispose();
1472
            }
1473
        }
1474
    }
1475

    
1476
    @Override
1477
    public boolean isEditing() {
1478
        return mode == MODE_FULLEDIT;
1479
    }
1480

    
1481
    @Override
1482
    public boolean isAppending() {
1483
        return mode == MODE_APPEND;
1484
    }
1485

    
1486
    @Override
1487
    synchronized public void update(EditableFeatureType type)
1488
            throws DataException {
1489
        try {
1490
            if (type == null) {
1491
                throw new NullFeatureTypeException(getName());
1492
            }
1493

    
1494
            switch (this.mode) {
1495
                case MODE_QUERY:
1496
                    if (type.hasOnlyMetadataChanges(this.defaultFeatureType)) {
1497
                        if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1498
                            return;
1499
                        }
1500
                        FeatureType theType = type.getNotEditableCopy();
1501
                        if (defaultFeatureType.getId().equals(theType.getId())) {
1502
                            defaultFeatureType = theType;
1503
                        }
1504
                        List newtypes = new ArrayList();
1505
                        for (FeatureType featureType : this.featureTypes) {
1506
                            if (featureType.getId().equals(theType.getId())) {
1507
                                newtypes.add(theType);
1508
                            } else {
1509
                                newtypes.add(featureType);
1510
                            }
1511
                        }
1512
                        this.featureTypes = newtypes;
1513
                        saveDALFile();
1514
                        notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1515
                    }
1516

    
1517
                    break;
1518
                case MODE_FULLEDIT:
1519
                    if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1520
                        return;
1521
                    }
1522
                    newVersionOfUpdate();
1523

    
1524
                    FeatureType oldt = type.getSource().getCopy();
1525
                    FeatureType newt = type.getCopy();
1526
                    commands.update(newt, oldt);
1527
                    hasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1528
                    notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1529
                    break;
1530
                case MODE_APPEND:
1531
                case MODE_PASS_THROUGH:
1532
                    throw new NeedEditingModeException(this.getName());
1533

    
1534
            }
1535
        } catch (Exception e) {
1536
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1537
        }
1538
    }
1539

    
1540
    @Override
1541
    public void delete(Feature feature) throws DataException {
1542
        switch (this.mode) {
1543
            case MODE_PASS_THROUGH:
1544
                checkIsOwnFeature(feature);
1545
                if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1546
                    return;
1547
                }
1548
                this.provider.passThroughDelete((FeatureReferenceProviderServices) feature.getReference());
1549
                notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1550
                break;
1551
            default:
1552
                this.commands.delete(feature);
1553
                break;
1554

    
1555
        }
1556
    }
1557

    
1558
    @Override
1559
    public void delete(String filter) {
1560
        if (StringUtils.isBlank(filter)) {
1561
            return;
1562
        }
1563
        this.delete(ExpressionUtils.createExpression(filter));
1564
    }
1565

    
1566
    @Override
1567
    public void delete(Expression filter) {
1568
        if (filter == null) {
1569
            return;
1570
        }
1571
        boolean pendingFinishEditing = false;
1572
        DisposableFeatureSetIterable features = null;
1573
        try {
1574
            switch (this.mode) {
1575
                case MODE_QUERY:
1576
                    pendingFinishEditing = true;
1577
                    this.edit();
1578
                    break;
1579
                case MODE_APPEND:
1580
                    throw new IllegalStateException("Delete not allowed in append mode.");
1581
                case MODE_FULLEDIT:
1582
                    break;
1583
                case MODE_PASS_THROUGH:
1584
                    if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, filter).isCanceled()) {
1585
                        return;
1586
                    }
1587
                    this.provider.passThroughDelete(filter);
1588
                    notifyChange(FeatureStoreNotification.AFTER_DELETE, filter);                    
1589
                    return;
1590
                default:
1591
                    throw new IllegalStateException("Mode " + this.mode + " not supported.");
1592
            }
1593

    
1594
            FeatureSet fset = this.getFeatureSet(filter);
1595
            features = fset.iterable();
1596
            for (Feature f : features) {
1597
                fset.delete(f);
1598
            }
1599
        } catch (DataException ex) {
1600
            throw new DataRuntimeException(ex.getFormatString(), ex.getMessageKey(), ex.getCode()) {
1601
            };
1602
        } catch (Exception ex) {
1603
            throw new RuntimeException("Can't delete features (" + filter.getPhrase() + ").", ex);
1604
        } finally {
1605
            if (pendingFinishEditing) {
1606
                this.finishEditingQuietly();
1607
            }
1608
            DisposeUtils.disposeQuietly(features);
1609
        }
1610
    }
1611

    
1612
    synchronized public void doDelete(Feature feature) throws DataException {
1613
        if (feature == null) {
1614
            throw new IllegalArgumentException("feature argument can't be null.");
1615
        }
1616
        try {
1617
            checkInEditingMode();
1618
            checkIsOwnFeature(feature);
1619
            if (feature instanceof EditableFeature && !((EditableFeature)feature).isUpdatable()) {
1620
                //La feature no est? persistida en disco
1621
                throw new StoreDeleteEditableFeatureException(getName());
1622
            }
1623
            if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1624
                return;
1625
            }
1626

    
1627
            //Update the featureManager and the spatialManager
1628
            featureManager.delete(feature);
1629
            spatialManager.deleteFeature(feature);
1630

    
1631
            newVersionOfUpdate();
1632
            hasStrongChanges = true;
1633
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1634
        } catch (Exception e) {
1635
            throw new StoreDeleteFeatureException(e, this.getName());
1636
        }
1637
    }
1638

    
1639
    @Override
1640
    public synchronized void insert(FeatureSet set) throws DataException {
1641
        switch (mode) {
1642
            case MODE_QUERY:
1643
                throw new NeedEditingModeException(this.getName());
1644

    
1645
            case MODE_APPEND:
1646
            case MODE_FULLEDIT:
1647
            case MODE_PASS_THROUGH:
1648
            try {
1649
                set.accept((Object obj) -> {
1650
                    EditableFeature ef = createNewFeature((Feature) obj);
1651
                    insert(ef);
1652
                });
1653
            } catch (BaseException ex) {
1654
                throw new StoreInsertFeatureException(ex, this.getName());
1655
            }
1656
            break;
1657
        }
1658
    }
1659

    
1660
    private static EditableFeature lastChangedFeature = null;
1661

    
1662
    @Override
1663
    public synchronized void insert(EditableFeature feature)
1664
            throws DataException {
1665
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1666
        try {
1667
            switch (mode) {
1668
                case MODE_QUERY:
1669
                    throw new NeedEditingModeException(this.getName());
1670

    
1671
                case MODE_APPEND:
1672
                    checkIsOwnFeature(feature);
1673
                    if (feature.isUpdatable()) {
1674
                        throw new NoNewFeatureInsertException(this.getName());
1675
                    }
1676
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1677
                        return;
1678
                    }
1679
                    this.featureCount = null;
1680
                    feature.validate(CHECK_RULES_AT_EDITING);
1681
                    provider.append(((DefaultEditableFeature) feature).getData());
1682
                    hasStrongChanges = true;
1683
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1684
                    break;
1685

    
1686
                case MODE_FULLEDIT:
1687
                    if (feature.isUpdatable()) {
1688
                        throw new NoNewFeatureInsertException(this.getName());
1689
                    }
1690
                    feature.validate(CHECK_RULES_AT_EDITING);
1691
                    commands.insert(feature);
1692
                    break;
1693

    
1694
                case MODE_PASS_THROUGH:
1695
                    checkIsOwnFeature(feature);
1696
                    if (feature.isUpdatable()) {
1697
                        throw new NoNewFeatureInsertException(this.getName());
1698
                    }
1699
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1700
                        return;
1701
                    }
1702
                    feature.validate(CHECK_RULES_AT_EDITING);
1703
                    this.provider.passThroughInsert(((DefaultEditableFeature) feature).getData());
1704
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1705
                    break;
1706
            }
1707
        } catch (Exception e) {
1708
            throw new StoreInsertFeatureException(e, this.getName());
1709
        }
1710
    }
1711

    
1712
    synchronized public void doInsert(EditableFeature feature)
1713
            throws DataException {
1714
        checkIsOwnFeature(feature);
1715

    
1716
        waitForIndexes();
1717

    
1718
        if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1719
            return;
1720
        }
1721
        newVersionOfUpdate();
1722
        if ((lastChangedFeature == null)
1723
                || (lastChangedFeature.getSource() != feature.getSource())) {
1724
            lastChangedFeature = feature;
1725
            feature.validate(CHECK_RULES_AT_EDITING);
1726
            lastChangedFeature = null;
1727
        }
1728
        //Update the featureManager and the spatialManager
1729
        ((DefaultFeature) feature).setInserted(true);
1730
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1731

    
1732
        featureManager.add(feature);
1733
        spatialManager.insertFeature(newFeature);
1734

    
1735
        hasStrongChanges = true;
1736
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1737
    }
1738

    
1739
    @Override
1740
    public void update(EditableFeature feature)
1741
            throws DataException {
1742
        switch (this.mode) {
1743
            case MODE_PASS_THROUGH:
1744
                checkIsOwnFeature(feature);
1745
                if (!feature.isUpdatable()) {
1746
                    throw new NoNewFeatureInsertException(this.getName());
1747
                }
1748
                if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1749
                    return;
1750
                }
1751
                feature.validate(CHECK_RULES_AT_EDITING);
1752
                this.provider.passThroughUpdate(((DefaultEditableFeature) feature).getData());
1753
                notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1754
                break;
1755
            case MODE_FULLEDIT:
1756
                if (feature.isUpdatable()) {
1757
                    commands.update(feature, feature.getSource());
1758
                    return;
1759
                }
1760
                // FIXME: Deberiamos lanzar aqui un error en lugar de hacer el insert.
1761
                //        O lanzar un mensaje al log?
1762
                insert(feature);
1763
                break;
1764
            default:
1765
                throw new NeedEditingModeException(this.getName());
1766
        }
1767
    }
1768

    
1769
    @Override
1770
    public void update(Object... parameters) throws DataException {
1771
        if (parameters.length == 1) {
1772
            Object param0 = parameters[0];
1773
            if (param0 instanceof EditableFeature) {
1774
                this.update((EditableFeature) param0);
1775
            } else if (param0 instanceof EditableFeatureType) {
1776
                this.update((EditableFeatureType) param0);
1777
            } else {
1778
                throw new IllegalArgumentException("Type of first parameter isn't supported");
1779
            }
1780
            return;
1781
        }
1782

    
1783
        Expression filter = null;
1784
        long end = parameters.length;
1785
        if (parameters.length % 2 == 1) { //IMPAR
1786
            Object param = parameters[parameters.length - 1];
1787
            if (param != null) {
1788
                if (param instanceof Expression) {
1789
                    filter = (Expression) param;
1790
                } else {
1791
                    filter = ExpressionUtils.createExpression(param.toString());
1792
                }
1793
            }
1794
        } else {
1795
            end = parameters.length - 1;
1796
        }
1797

    
1798
        switch (this.mode) {
1799
            case MODE_PASS_THROUGH:
1800
                this.provider.passThroughUpdate(
1801
                        //                    this.getName(), 
1802
                        parameters,
1803
                        filter);
1804
                break;
1805
            case MODE_FULLEDIT:
1806
                FeatureSet set = this.getFeatureSet(filter);
1807
                DisposableIterator it = set.fastIterator();
1808
                while (it.hasNext()) {
1809
                    Feature feature = (Feature) it.next();
1810
                    EditableFeature ef = feature.getEditable();
1811
                    for (int i = 0; i < end; i += 2) {
1812
                        String name = (String) parameters[i];
1813
                        Object value = parameters[i + 1];
1814
                        ef.set(name, value);
1815
                    }
1816
                    set.update(ef);
1817
                }
1818
                DisposeUtils.disposeQuietly(it);
1819
                DisposeUtils.disposeQuietly(set);
1820
                break;
1821
            default:
1822
                throw new NeedEditingModeException(this.getName());
1823
        }
1824
    }
1825

    
1826
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1827
            throws DataException {
1828
        try {
1829
            checkInEditingMode();
1830
            checkIsOwnFeature(feature);
1831
            if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1832
                return;
1833
            }
1834
            newVersionOfUpdate();
1835
            if ((lastChangedFeature == null)
1836
                    || (lastChangedFeature.getSource() != feature.getSource())) {
1837
                lastChangedFeature = feature;
1838
                feature.validate(CHECK_RULES_AT_EDITING);
1839
                lastChangedFeature = null;
1840
            }
1841

    
1842
            //Update the featureManager and the spatialManager
1843
            Feature newf = feature.getNotEditableCopy();
1844
            featureManager.update(feature, oldFeature);
1845
            spatialManager.updateFeature(newf, oldFeature);
1846

    
1847
            hasStrongChanges = true;
1848
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1849
        } catch (Exception e) {
1850
            throw new StoreUpdateFeatureException(e, this.getName());
1851
        }
1852
    }
1853

    
1854
    @Override
1855
    synchronized public void redo() throws RedoException {
1856
        Command redo = commands.getNextRedoCommand();
1857
        try {
1858
            checkInEditingMode();
1859
        } catch (NeedEditingModeException ex) {
1860
            throw new RedoException(redo, ex);
1861
        }
1862
        if (notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled()) {
1863
            return;
1864
        }
1865
        newVersionOfUpdate();
1866
        commands.redo();
1867
        hasStrongChanges = true;
1868
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1869
    }
1870

    
1871
    @Override
1872
    synchronized public void undo() throws UndoException {
1873
        Command undo = commands.getNextUndoCommand();
1874
        try {
1875
            checkInEditingMode();
1876
        } catch (NeedEditingModeException ex) {
1877
            throw new UndoException(undo, ex);
1878
        }
1879
        if (notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled()) {
1880
            return;
1881
        }
1882
        newVersionOfUpdate();
1883
        commands.undo();
1884
        hasStrongChanges = true;
1885
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1886
    }
1887

    
1888
    @Override
1889
    public List getRedoInfos() {
1890
        if (isEditing() && (commands != null)) {
1891
            return commands.getRedoInfos();
1892
        } else {
1893
            return null;
1894
        }
1895
    }
1896

    
1897
    @Override
1898
    public List getUndoInfos() {
1899
        if (isEditing() && (commands != null)) {
1900
            return commands.getUndoInfos();
1901
        } else {
1902
            return null;
1903
        }
1904
    }
1905

    
1906
    public synchronized FeatureCommandsStack getCommandsStack()
1907
            throws DataException {
1908
        checkInEditingMode();
1909
        return commands;
1910
    }
1911

    
1912
    @Override
1913
    public boolean cancelEditingQuietly() {
1914
        try {
1915
            this.cancelEditing();
1916
            return true;
1917
        } catch (Exception ex) {
1918
            LOGGER.debug("Can't cancel editing", ex);
1919
            return false;
1920
        }
1921
    }
1922

    
1923
    @Override
1924
    synchronized public void cancelEditing() throws DataException {
1925
        if (spatialManager != null) {
1926
            spatialManager.cancelModifies();
1927
        }
1928
        try {
1929
            switch (mode) {
1930
                case MODE_QUERY:
1931
                    throw new NeedEditingModeException(this.getName());
1932

    
1933
                case MODE_APPEND:
1934
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1935
                        return;
1936
                    }
1937
                    provider.abortAppend();
1938
                    exitEditingMode();
1939
                    ((FeatureSelection) this.getSelection()).deselectAll();
1940
                    updateIndexes();
1941
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1942
                    break;
1943

    
1944
                case MODE_FULLEDIT:
1945
                    boolean clearSelection = this.hasStrongChanges;
1946
                    if (this.selection instanceof FeatureReferenceSelection) {
1947
                        clearSelection = this.hasStrongChanges || this.featureManager.hasNews();
1948
                    }
1949
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1950
                        return;
1951
                    }
1952
                    exitEditingMode();
1953
                    if (clearSelection) {
1954
                        ((FeatureSelection) this.getSelection()).deselectAll();
1955
                    }
1956
                    updateIndexes();
1957
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1958
                    break;
1959

    
1960
                case MODE_PASS_THROUGH:
1961
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1962
                        return;
1963
                    }
1964
                    exitEditingMode();
1965
                    ((FeatureSelection) this.getSelection()).deselectAll();
1966
                    updateIndexes();
1967
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1968
                    break;
1969
            }
1970
        } catch (Exception e) {
1971
            throw new StoreCancelEditingException(e, this.getName());
1972
        }
1973
    }
1974

    
1975
    @Override
1976
    public boolean finishEditingQuietly() {
1977
        try {
1978
            this.finishEditing();
1979
            return true;
1980
        } catch (Exception ex) {
1981
            LOGGER.debug("Can't finish editing", ex);
1982
            return false;
1983
        }
1984
    }
1985

    
1986
    @Override
1987
    synchronized public void finishEditing() throws DataException {
1988
        LOGGER.debug("finish editing of mode: {}", mode);
1989
        try {
1990
            Map<String, List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1991
            switch (mode) {
1992
                case MODE_QUERY:
1993
                    throw new NeedEditingModeException(this.getName());
1994

    
1995
                case MODE_APPEND:
1996
                    if (selection != null) {
1997
                        selection = null;
1998
                    }
1999
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2000
                        return;
2001
                    }
2002
                    saveDALFile();
2003
                    provider.endAppend();
2004
                    exitEditingMode();
2005
                    this.updateComputedFields(computedFields);
2006
                    loadDALFile();
2007
                    updateIndexes();
2008
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2009
                    break;
2010

    
2011
                case MODE_FULLEDIT:
2012
                    if (featureManager.hasChanges() || featureTypeManager.hasChanges()) {
2013
                        if (hasStrongChanges && !this.allowWrite()) {
2014
                            throw new WriteNotAllowedException(getName());
2015
                        }
2016
                        if (notifyChange(FeatureStoreNotification.PREPARING_FINISHEDITING).isCanceled()) {
2017
                            return;
2018
                        }
2019
                        if (hasStrongChanges) {
2020
                            validateFeaturesAtFinishEditing();
2021
                        }
2022
                        if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING,
2023
                                featureManager.getDeleted(),
2024
                                featureManager.getInsertedFeatures(),
2025
                                featureManager.getUpdatedFeatures(),
2026
                                featureTypeManager.getFeatureTypesChanged().iterator(),
2027
                                featureManager.isSelectionCompromised()).isCanceled()) {
2028
                            return;
2029
                        }
2030
                        saveDALFile();
2031
                        if (featureManager.isSelectionCompromised() && selection != null) {
2032
                            selection = null;
2033
                        }
2034
                        if (hasStrongChanges) {
2035
                            // This will throw a PerformEditingException if the provider
2036
                            // does not accept the changes (for example, an invalid field name)
2037
                            provider.performChanges(featureManager.getDeleted(),
2038
                                    featureManager.getInserted(),
2039
                                    featureManager.getUpdated(),
2040
                                    removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2041

    
2042
                        }
2043
                        this.updateComputedFields(computedFields);
2044
                        exitEditingMode();
2045
                        loadDALFile();
2046
                        updateIndexes();
2047
                        notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2048
                    } else {
2049
                        exitEditingMode();
2050
                    }
2051
                    break;
2052
                case MODE_PASS_THROUGH:
2053
                    if (selection != null) {
2054
                        selection = null;
2055
                    }
2056
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2057
                        return;
2058
                    }
2059
                    exitEditingMode();
2060
                    updateIndexes();
2061
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2062
                    break;
2063
            }
2064
        } catch (ValidateFeaturesException | WriteNotAllowedException ex) {
2065
            // Don't notify failed.
2066
            throw ex;
2067
        } catch (PerformEditingException pee) {
2068
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2069
            throw new WriteException(provider.getSourceId().toString(), pee);
2070
        } catch (Exception e) {
2071
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2072
            throw new FinishEditingException(e);
2073
        }
2074
    }
2075

    
2076
    @Override
2077
    public String getEditingSession() {
2078
        return this.editingSessionCode;
2079
    }
2080

    
2081
    private Map<String, List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
2082
        Map<String, List<FeatureAttributeDescriptor>> r = new HashMap<>();
2083

    
2084
        List<FeatureType> theTypes = new ArrayList<>();
2085
        theTypes.addAll(this.getFeatureTypes());
2086
        theTypes.add(this.getDefaultFeatureType());
2087
        for (int n = 0; n < theTypes.size(); n++) {
2088
            FeatureType type = theTypes.get(n);
2089
            for (FeatureAttributeDescriptor attrdesc : type) {
2090
                FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
2091
                if (emulator != null) {
2092
                    List<FeatureAttributeDescriptor> l = r.get(type.getId());
2093
                    if (l == null) {
2094
                        l = new ArrayList<>();
2095
                        r.put(type.getId(), l);
2096
                    }
2097
                    l.add(attrdesc);
2098
                }
2099
            }
2100
        }
2101
        return r;
2102
    }
2103

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

    
2106
        List<FeatureType> theTypes = new ArrayList<>();
2107
        theTypes.addAll(this.getFeatureTypes());
2108
        theTypes.add(this.getDefaultFeatureType());
2109
        for (int n = 0; n < theTypes.size(); n++) {
2110
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
2111
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
2112
            if (x != null && !x.isEmpty()) {
2113
                for (FeatureAttributeDescriptor attrdesc : x) {
2114
                    if (type.get(attrdesc.getName()) == null) {
2115
                        type.add(attrdesc);
2116
                    }
2117
                }
2118
            }
2119
        }
2120

    
2121
    }
2122

    
2123
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
2124
        // FIXME: Falta por implementar
2125
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
2126
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
2127
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
2128
//                if (attributeDescriptor.isComputed()) {
2129
//                    target.remove(attributeDescriptor.getName());
2130
//                }
2131
//            }
2132
//        }
2133
        return ftypes;
2134
    }
2135

    
2136
    private void saveDALFile() {
2137
        if( this.ignoreDALResource ) {
2138
            return;
2139
        }
2140
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2141
        ResourcesStorage theResourcesStorage = null;
2142
        try {
2143
            theResourcesStorage = this.getResourcesStorage();
2144
            if (theResourcesStorage == null || theResourcesStorage.isReadOnly()) {
2145
                return;
2146
            }
2147
            resource = theResourcesStorage.getResource("dal");
2148
            if (resource == null || resource.isReadOnly()) {
2149
                return;
2150
            }
2151
            DALFile dalFile = DALFile.getDALFile();
2152
            dalFile.setStore(this);
2153
            if (!dalFile.isEmpty()) {
2154
                dalFile.write(resource);
2155
            }
2156
        } catch (Throwable ex) {
2157
            LOGGER.warn("Can't save DAL resource", ex);
2158
        } finally {
2159
            IOUtils.closeQuietly(resource);
2160
            DisposeUtils.disposeQuietly(theResourcesStorage);
2161
        }
2162
    }
2163

    
2164
    private void loadDALFile() {
2165
        if( this.ignoreDALResource ) {
2166
            return;
2167
        }
2168
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2169
        ResourcesStorage theResourcesStorage = null;
2170
        try {
2171
            theResourcesStorage = this.getResourcesStorage();
2172
            if (theResourcesStorage == null) {
2173
                return;
2174
            }
2175
            resource = theResourcesStorage.getResource("dal");
2176
            if (resource == null || !resource.exists()) {
2177
                return;
2178
            }
2179
            DALFile dalFile = DALFile.getDALFile(resource);
2180
            if (!dalFile.isEmpty()) {
2181
                dalFile.updateStore(this);
2182
            }
2183
        } catch (Throwable ex) {
2184
            if (resource == null || theResourcesStorage == null) {
2185
                if (theResourcesStorage == null) {
2186
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=null)", ex);
2187
                } else {
2188
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2189
                }
2190
            } else {
2191
                LOGGER.warn("Can't load DAL resource (resname=" + resource.getName() + ", resurl=" + Objects.toString(resource.getURL()) + ", storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2192
            }
2193
        } finally {
2194
            IOUtils.closeQuietly(resource);
2195
            DisposeUtils.disposeQuietly(theResourcesStorage);
2196
        }
2197
    }
2198

    
2199
    /**
2200
     * Save changes in the provider without leaving the edit mode. Do not call
2201
     * observers to communicate a change of ediding mode. The operation's
2202
     * history is eliminated to prevent inconsistencies in the data.
2203
     *
2204
     * @throws DataException
2205
     */
2206
    @Override
2207
    synchronized public void commitChanges() throws DataException {
2208
        LOGGER.debug("commitChanges of mode: {}", mode);
2209
        if (!canCommitChanges()) {
2210
            throw new WriteNotAllowedException(getName());
2211
        }
2212
        try {
2213
            switch (mode) {
2214
                case MODE_QUERY:
2215
                    throw new NeedEditingModeException(this.getName());
2216

    
2217
                case MODE_APPEND:
2218
                    this.provider.endAppend();
2219
                    exitEditingMode();
2220
                    invalidateIndexes();
2221
                    this.provider.beginAppend();
2222
                    break;
2223

    
2224
                case MODE_FULLEDIT:
2225
                    if (hasStrongChanges && !this.allowWrite()) {
2226
                        throw new WriteNotAllowedException(getName());
2227
                    }
2228
                    // FIXME: OOhh!!!! no se disparan eventos, VCSGis no se entera de estos cambios.
2229
                    if (hasStrongChanges) {
2230
                        validateFeaturesAtFinishEditing();
2231
                        provider.performChanges(featureManager.getDeleted(),
2232
                                featureManager.getInserted(),
2233
                                featureManager.getUpdated(),
2234
                                removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2235
                    }
2236
                    invalidateIndexes();
2237
                    featureManager = new FeatureManager(this);
2238
                    featureTypeManager = new FeatureTypeManager(this);
2239
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
2240

    
2241
                    commands
2242
                            = new DefaultFeatureCommandsStack(this, featureManager,
2243
                                    spatialManager, featureTypeManager);
2244
                    featureCount = null;
2245
                    hasStrongChanges = false;
2246
                    break;
2247
            }
2248
        } catch (Exception e) {
2249
            throw new FinishEditingException(e);
2250
        }
2251
    }
2252

    
2253
    @Override
2254
    synchronized public boolean canCommitChanges() throws DataException {
2255
        if (!this.allowWrite()) {
2256
            return false;
2257
        }
2258
        switch (mode) {
2259
            default:
2260
            case MODE_QUERY:
2261
                return false;
2262

    
2263
            case MODE_APPEND:
2264
                return true;
2265

    
2266
            case MODE_FULLEDIT:
2267
                List types = this.getFeatureTypes();
2268
                for (int i = 0; i < types.size(); i++) {
2269
                    Object type = types.get(i);
2270
                    if (type instanceof DefaultEditableFeatureType) {
2271
                        if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
2272
                            return false;
2273
                        }
2274
                    }
2275
                }
2276
                return true;
2277
        }
2278
    }
2279

    
2280
    @Override
2281
    public void beginEditingGroup(String description)
2282
            throws NeedEditingModeException {
2283
        checkInEditingMode();
2284
        commands.startComplex(description);
2285
    }
2286

    
2287
    @Override
2288
    public void endEditingGroup() throws NeedEditingModeException {
2289
        checkInEditingMode();
2290
        commands.endComplex();
2291
    }
2292

    
2293
    @Override
2294
    public boolean isAppendModeSupported() {
2295
        return this.provider.supportsAppendMode();
2296
    }
2297

    
2298
    @Override
2299
    public void export(DataServerExplorer explorer, String provider,
2300
            NewFeatureStoreParameters params, String name) throws DataException {
2301

    
2302
        if (this.getFeatureTypes().size() != 1) {
2303
            throw new NotYetImplemented(
2304
                    "export whith more than one type not yet implemented");
2305
        }
2306
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2307
        FeatureStore target = null;
2308
        FeatureSet features = null;
2309
        DisposableIterator iterator = null;
2310
        try {
2311
            FeatureType type = this.getDefaultFeatureType();
2312
            if ((params.getDefaultFeatureType() == null)
2313
                    || (params.getDefaultFeatureType().size() == 0)) {
2314
                params.setDefaultFeatureType(type.getEditable());
2315

    
2316
            }
2317
            explorer.add(provider, params, true);
2318
            DataManager manager = DALLocator.getDataManager();
2319

    
2320
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2321
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2322

    
2323
            target = (FeatureStore) manager.openStore(provider, openParams);
2324
            FeatureType targetType = target.getDefaultFeatureType();
2325

    
2326
            target.edit(MODE_APPEND);
2327
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2328
            if (featureSelection.getSize() > 0) {
2329
                features = this.getFeatureSelection();
2330
            } else {
2331
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2332
                    FeatureQuery query = createFeatureQuery();
2333
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2334
                        query.getOrder().add(pkattr.getName(), true);
2335
                    }
2336
                    features = this.getFeatureSet(query);
2337
                } else {
2338
                    features = this.getFeatureSet();
2339
                }
2340
            }
2341
            iterator = features.fastIterator();
2342
            while (iterator.hasNext()) {
2343
                DefaultFeature feature = (DefaultFeature) iterator.next();
2344
                target.insert(target.createNewFeature(targetType, feature));
2345
            }
2346
            target.finishEditing();
2347
            target.dispose();
2348
        } catch (Exception e) {
2349
            throw new DataExportException(e, params.toString());
2350
        } finally {
2351
            dispose(iterator);
2352
            dispose(features);
2353
            dispose(target);
2354
        }
2355
    }
2356

    
2357
    @Override
2358
    public void copyTo(final FeatureStore target) {
2359
        boolean finishEditingAtEnd = false;
2360
        try {
2361
            if (!target.isEditing() && !target.isAppending()) {
2362
                finishEditingAtEnd = true;
2363
                target.edit(MODE_APPEND);
2364
            }
2365
            this.accept((Object obj) -> {
2366
                Feature f_src = (Feature) obj;
2367
                EditableFeature f_dst = target.createNewFeature(f_src);
2368
                target.insert(f_dst);
2369
            });
2370
            if (finishEditingAtEnd) {
2371
                target.finishEditing();
2372
            }
2373

    
2374
        } catch (Exception ex) {
2375
            try {
2376
                if (finishEditingAtEnd) {
2377
                    target.cancelEditing();
2378
                }
2379
            } catch (Exception ex1) {
2380
            }
2381
            throw new RuntimeException("Can't copy store.", ex);
2382
        }
2383

    
2384
    }
2385

    
2386
    //
2387
    // ====================================================================
2388
    // Obtencion de datos
2389
    // getDataCollection, getFeatureCollection
2390
    //
2391
    @Override
2392
    public DataSet getDataSet() throws DataException {
2393
        return this.getFeatureSet((FeatureQuery)null);
2394
    }
2395

    
2396
    @Override
2397
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2398
        return this.getFeatureSet((FeatureQuery)dataQuery);
2399
    }
2400

    
2401
    @Override
2402
    public void getDataSet(Observer observer) throws DataException {
2403
        checkNotInAppendMode();
2404
        this.getFeatureSet(null, observer);
2405
    }
2406

    
2407
    @Override
2408
    public void getDataSet(DataQuery dataQuery, Observer observer)
2409
            throws DataException {
2410
        checkNotInAppendMode();
2411
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2412
    }
2413

    
2414
    @Override
2415
    public FeatureSet getFeatureSet() throws DataException {
2416
        return this.getFeatureSet((FeatureQuery) null);
2417
    }
2418

    
2419
    @Override
2420
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2421
            throws DataException {
2422
        checkNotInAppendMode();
2423
        if (featureQuery == null) {
2424
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2425
        } else if( featureQuery.hasAggregateFunctions() || featureQuery.hasGroupByColumns() ) {
2426
            // Si tenemos datos por persistir en la bbdd (bien por que estamos en modo 
2427
            // append(batchsize) o por que estamos en modo fulledit y hay cambios
2428
            // realizados, las agrupaciones y funciones de agregado, como las gestiona
2429
            // la bbdd, pueden no dar resultados correctos. Asi que no dejamos hacer
2430
            // estas operaciones.
2431
            if( this.mode==MODE_APPEND  ) {
2432
                throw new UnsupportedOperationException("Can't create a set with aggregate functions or group by columns in append mode");
2433
            }
2434
            if( this.mode == MODE_FULLEDIT ) {
2435
                if( this.featureManager==null || this.featureManager.getPendingChangesCount()>0 ) {
2436
                   throw new UnsupportedOperationException("Can't create a set with aggregate functions or group by columns with editing changes");
2437
                }
2438
            }
2439
        }
2440
        return new DefaultFeatureSet(this, featureQuery);
2441
    }
2442

    
2443
    @Override
2444
    public FeatureSet getFeatureSet(String filter) throws DataException {
2445
        return this.getFeatureSet(filter, null, true);
2446
    }
2447

    
2448
    @Override
2449
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2450
        return this.getFeatureSet(filter, sortBy, true);
2451
    }
2452

    
2453
    @Override
2454
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2455
        return this.getFeatureSet(filter, null, true);
2456
    }
2457

    
2458
    @Override
2459
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2460
        return this.getFeatureSet(filter, sortBy, true);
2461
    }
2462

    
2463
    @Override
2464
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2465
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2466
        return this.getFeatureSet(query);
2467
    }
2468

    
2469
    @Override
2470
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2471
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2472
        return this.getFeatureSet(query);
2473
    }
2474

    
2475
    @Override
2476
    public List<Feature> getFeatures(String filter) {
2477
        return this.getFeatures(filter, null, true);
2478
    }
2479

    
2480
    @Override
2481
    public List<Feature> getFeatures(String filter, String sortBy) {
2482
        return this.getFeatures(filter, sortBy, true);
2483
    }
2484

    
2485
    @Override
2486
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc) {
2487
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2488
        return this.getFeatures(query, 0);
2489
    }
2490

    
2491
    @Override
2492
    public List<Feature> getFeatures(Expression filter) {
2493
        return this.getFeatures(filter, null, true);
2494
    }
2495

    
2496
    @Override
2497
    public List<Feature> getFeatures(Expression filter, String sortBy) {
2498
        return this.getFeatures(filter, sortBy, true);
2499
    }
2500

    
2501
    @Override
2502
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc) {
2503
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2504
        return this.getFeatures(query, 0);
2505
    }
2506

    
2507
    @Override
2508
    public List<Feature> getFeatures(FeatureQuery query) {
2509
        return this.getFeatures(query, 0);
2510
    }
2511

    
2512
    @Override
2513
    public List<Feature> getFeatures(FeatureQuery query, int pageSize) {
2514
        try {
2515
            if (pageSize <= 0) {
2516
                pageSize = 100;
2517
            }
2518
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2519
            return pager.asList();
2520
        } catch (BaseException ex) {
2521
            throw new RuntimeException("Can't create the list of features.", ex);
2522
        }
2523
    }
2524
        
2525
    @Override
2526
    public List<Feature> getFeatures() {
2527
        return this.getFeatures(null, 0);
2528
    }
2529

    
2530
    @Override
2531
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2532
        return this.getFeatures64(null, 0);
2533
    }
2534

    
2535
    @Override
2536
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2537
        return this.getFeatures64(filter, null, true);
2538
    }
2539

    
2540
    @Override
2541
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc) {
2542
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2543
        return this.getFeatures64(query, 0);
2544
    }
2545

    
2546
    @Override
2547
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize) {
2548
        try {
2549
            if (pageSize <= 0) {
2550
                pageSize = 100;
2551
            }
2552
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2553
            return pager;
2554
        } catch (BaseException ex) {
2555
            throw new RuntimeException("Can't create the list of features.", ex);
2556
        }
2557
    }
2558

    
2559
    @Override
2560
    public Feature first() throws DataException {
2561
        return this.findFirst((FeatureQuery) null);
2562
    }
2563

    
2564
    @Override
2565
    public Feature findFirst(String filter) throws DataException {
2566
        return this.findFirst(filter, (String) null, true);
2567
    }
2568

    
2569
    @Override
2570
    public Feature findFirst(String filter, String sortBy) throws DataException {
2571
        return this.findFirst(filter, sortBy, true);
2572
    }
2573

    
2574
    @Override
2575
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2576
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2577
        return findFirst(query);
2578
    }
2579

    
2580
    @Override
2581
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2582
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2583
        return findFirst(query);
2584
    }
2585

    
2586
    @Override
2587
    public Feature findFirst(Expression filter) throws DataException {
2588
        return this.findFirst(filter, (String) null, true);
2589
    }
2590

    
2591
    @Override
2592
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2593
        return this.findFirst(filter, sortBy, true);
2594
    }
2595

    
2596
    @Override
2597
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2598
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2599
        return findFirst(query);
2600
    }
2601

    
2602
    @Override
2603
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2604
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2605
        return findFirst(query);
2606
    }
2607

    
2608
    @Override
2609
    public Feature findFirst(FeatureQuery query) throws DataException {
2610
        if (query == null) {
2611
            query = this.createFeatureQuery();
2612
        } else {
2613
            query = query.getCopy();
2614
        }
2615
        query.setLimit(1);
2616
        final MutableObject<Feature> feature = new MutableObject<>();
2617
        try {
2618
            this.accept((Object obj) -> {
2619
                feature.setValue((Feature) obj);
2620
                throw new VisitCanceledException();
2621
            }, query);
2622
        } catch (VisitCanceledException ex) {
2623

    
2624
        } catch (DataException ex) {
2625
            throw ex;
2626
        } catch (Exception ex) {
2627
            throw new RuntimeException("", ex);
2628
        }
2629
        return feature.getValue();
2630
    }
2631

    
2632
    @Override
2633
    public void accept(Visitor visitor) throws BaseException {
2634
        this.accept(visitor, null);
2635
    }
2636

    
2637
    @Override
2638
    public void accept(Visitor visitor, DataQuery dataQuery)
2639
            throws BaseException {
2640
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2641
        try {
2642
            set.accept(visitor);
2643
        } finally {
2644
            set.dispose();
2645
        }
2646
    }
2647

    
2648
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2649
            throws DataException {
2650
        DefaultFeatureType fType
2651
                = (DefaultFeatureType) this.getFeatureType(featureQuery
2652
                        .getFeatureTypeId());
2653
        if (featureQuery.hasAttributeNames()
2654
                || featureQuery.hasConstantsAttributeNames()
2655
                || fType.hasRequiredFields()) {
2656
            if (featureQuery.hasGroupByColumns()) {
2657
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false);
2658
            } else {
2659
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2660
            }
2661
        }
2662
        return fType;
2663
    }
2664

    
2665
    @Override
2666
    public void getFeatureSet(Observer observer) throws DataException {
2667
        checkNotInAppendMode();
2668
        this.getFeatureSet(null, observer);
2669
    }
2670

    
2671
    @Override
2672
    public void getFeatureSet(FeatureQuery query, Observer observer)
2673
            throws DataException {
2674
        class LoadInBackGround implements Runnable {
2675

    
2676
            private final FeatureStore store;
2677
            private final FeatureQuery query;
2678
            private final Observer observer;
2679

    
2680
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2681
                    Observer observer) {
2682
                this.store = store;
2683
                this.query = query;
2684
                this.observer = observer;
2685
            }
2686

    
2687
            void notify(FeatureStoreNotification theNotification) {
2688
                observer.update(store, theNotification);
2689
            }
2690

    
2691
            @Override
2692
            public void run() {
2693
                FeatureSet set = null;
2694
                try {
2695
                    set = store.getFeatureSet(query);
2696
                    notify(new DefaultFeatureStoreNotification(store,
2697
                            FeatureStoreNotification.LOAD_FINISHED, set));
2698
                } catch (Exception e) {
2699
                    notify(new DefaultFeatureStoreNotification(store,
2700
                            FeatureStoreNotification.LOAD_FINISHED, e));
2701
                } finally {
2702
                    dispose(set);
2703
                }
2704
            }
2705
        }
2706

    
2707
        checkNotInAppendMode();
2708
        if (query == null) {
2709
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2710
        }
2711
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2712
        Thread thread = new Thread(task, "Load Feature Set in background");
2713
        thread.start();
2714
    }
2715

    
2716
    @Override
2717
    public Feature getFeatureByReference(FeatureReference reference)
2718
            throws DataException {
2719
        checkNotInAppendMode();
2720
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2721
        FeatureType featureType;
2722
        if (ref.getFeatureTypeId() == null) {
2723
            featureType = this.getDefaultFeatureType();
2724
        } else {
2725
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2726
        }
2727
        return this.getFeatureByReference(reference, featureType);
2728
    }
2729

    
2730
    @Override
2731
    public Feature getFeatureByReference(FeatureReference reference,
2732
            FeatureType featureType) throws DataException {
2733
        checkNotInAppendMode();
2734
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2735
        if (this.mode == MODE_FULLEDIT) {
2736
            Feature f = featureManager.get(reference, this, featureType);
2737
            if (f != null) {
2738
                return f;
2739
            }
2740
        }
2741

    
2742
        FeatureType sourceFeatureType = featureType;
2743
        if (!this.transforms.isEmpty()) {
2744
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2745
        }
2746
        // TODO comprobar que el id es de este store
2747

    
2748
        DefaultFeature feature
2749
                = new DefaultFeature(this,
2750
                        this.provider.getFeatureProviderByReference(
2751
                                (FeatureReferenceProviderServices) reference, sourceFeatureType));
2752

    
2753
        if (!this.transforms.isEmpty()) {
2754
            return this.transforms.applyTransform(feature, featureType);
2755
        }
2756
        return feature;
2757
    }
2758

    
2759
    //
2760
    // ====================================================================
2761
    // Gestion de features
2762
    //
2763
    private FeatureType fixFeatureType(DefaultFeatureType type)
2764
            throws DataException {
2765
        FeatureType original = this.getDefaultFeatureType();
2766

    
2767
        if ((type == null) || type.equals(original)) {
2768
            return original;
2769
        } else {
2770
            if (!type.isSubtypeOf(original)) {
2771
                Iterator iter = this.getFeatureTypes().iterator();
2772
                FeatureType tmpType;
2773
                boolean found = false;
2774
                while (iter.hasNext()) {
2775
                    tmpType = (FeatureType) iter.next();
2776
                    if (type.equals(tmpType)) {
2777
                        return type;
2778

    
2779
                    } else if (type.isSubtypeOf(tmpType)) {
2780
                        found = true;
2781
                        original = tmpType;
2782
                        break;
2783
                    }
2784

    
2785
                }
2786
                if (!found) {
2787
                    throw new IllegalFeatureTypeException(getName());
2788
                }
2789
            }
2790
        }
2791

    
2792
        // Checks that type has all fields of pk
2793
        // else add the missing attributes at the end.
2794
        if (!original.hasOID()) {
2795
            // Gets original pk attributes
2796
            DefaultEditableFeatureType edOriginal
2797
                    = (DefaultEditableFeatureType) original.getEditable();
2798
            FeatureAttributeDescriptor orgAttr;
2799
            Iterator edOriginalIter = edOriginal.iterator();
2800
            while (edOriginalIter.hasNext()) {
2801
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2802
                if (!orgAttr.isPrimaryKey()) {
2803
                    edOriginalIter.remove();
2804
                }
2805
            }
2806

    
2807
            // Checks if all pk attributes are in type
2808
            Iterator typeIterator;
2809
            edOriginalIter = edOriginal.iterator();
2810
            FeatureAttributeDescriptor attr;
2811
            while (edOriginalIter.hasNext()) {
2812
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2813
                typeIterator = type.iterator();
2814
                while (typeIterator.hasNext()) {
2815
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2816
                    if (attr.getName().equals(orgAttr.getName())) {
2817
                        edOriginalIter.remove();
2818
                        break;
2819
                    }
2820
                }
2821
            }
2822

    
2823
            // add missing pk attributes if any
2824
            if (edOriginal.size() > 0) {
2825
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2826
                DefaultEditableFeatureType edType
2827
                        = (DefaultEditableFeatureType) original.getEditable();
2828
                edType.clear();
2829
                edType.addAll(type);
2830
                edType.addAll(edOriginal);
2831
                if (!isEditable) {
2832
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2833
                }
2834
            }
2835

    
2836
        }
2837

    
2838
        return type;
2839
    }
2840

    
2841
    private void validateFeaturesAtFinishEditing() throws ValidateFeaturesException {
2842
        try {
2843
            checkInEditingMode();
2844
            FeatureType type = this.getDefaultFeatureTypeQuietly();
2845
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
2846

    
2847
            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS : 0;
2848
            checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
2849
            if (checks == 0) {
2850
                return;
2851
            }
2852

    
2853
            Iterator<EditableFeature> features = new ChainedIterator<>(
2854
                    featureManager.getInsertedFeatures(),
2855
                    featureManager.getUpdatedFeatures()
2856
            );
2857
            while (features.hasNext()) {
2858
                EditableFeature feature = features.next();
2859
                rules.validate(feature, checks);
2860
            }
2861
        } catch (Exception ex) {
2862
            throw new ValidateFeaturesException(this.getName(), ex);
2863
        }
2864
    }
2865

    
2866
    @Override
2867
    public FeatureType getDefaultFeatureType() throws DataException {
2868
        try {
2869

    
2870
            if (isEditing()) {
2871
                FeatureType auxFeatureType
2872
                        = featureTypeManager.getType(defaultFeatureType.getId());
2873
                if (auxFeatureType != null) {
2874
                    return avoidEditable(auxFeatureType);
2875
                }
2876
            }
2877
            FeatureType type = this.transforms.getDefaultFeatureType();
2878
            if (type != null) {
2879
                return avoidEditable(type);
2880
            }
2881

    
2882
            return avoidEditable(defaultFeatureType);
2883

    
2884
        } catch (Exception e) {
2885
            throw new GetFeatureTypeException(e, getName());
2886
        }
2887
    }
2888

    
2889
    @Override
2890
    public FeatureType getDefaultFeatureTypeQuietly() {
2891
        try {
2892
            return this.getDefaultFeatureType();
2893
        } catch (Exception ex) {
2894
            return null;
2895
        }
2896
    }
2897

    
2898
    private FeatureType avoidEditable(FeatureType ft) {
2899
        if (ft instanceof EditableFeatureType) {
2900
            return ((EditableFeatureType) ft).getNotEditableCopy();
2901
        } else {
2902
            return ft;
2903
        }
2904
    }
2905

    
2906
    @Override
2907
    public FeatureType getFeatureType(String featureTypeId)
2908
            throws DataException {
2909
        if (featureTypeId == null) {
2910
            return this.getDefaultFeatureType();
2911
        }
2912
        try {
2913
            if (isEditing()) {
2914
                FeatureType auxFeatureType
2915
                        = featureTypeManager.getType(featureTypeId);
2916
                if (auxFeatureType != null) {
2917
                    return auxFeatureType;
2918
                }
2919
            }
2920
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2921
            if (type != null) {
2922
                return type;
2923
            }
2924
            Iterator iter = this.featureTypes.iterator();
2925
            while (iter.hasNext()) {
2926
                type = (FeatureType) iter.next();
2927
                if (type.getId().equals(featureTypeId)) {
2928
                    return type;
2929
                }
2930
            }
2931
            return null;
2932
        } catch (Exception e) {
2933
            throw new GetFeatureTypeException(e, getName());
2934
        }
2935
    }
2936

    
2937
    public FeatureType getProviderDefaultFeatureType() {
2938
        return defaultFeatureType;
2939
    }
2940

    
2941
    @Override
2942
    public List getFeatureTypes() throws DataException {
2943
        try {
2944
            List types;
2945
            if (isEditing()) {
2946
                types = new ArrayList();
2947
                for (FeatureType type : featureTypes) {
2948
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2949
                    if (typeaux != null) {
2950
                        types.add(typeaux);
2951
                    } else {
2952
                        types.add(type);
2953
                    }
2954
                }
2955
                Iterator it = featureTypeManager.newsIterator();
2956
                while (it.hasNext()) {
2957
                    FeatureType type = (FeatureType) it.next();
2958
                    types.add(type);
2959
                }
2960
            } else {
2961
                types = this.transforms.getFeatureTypes();
2962
                if (types == null) {
2963
                    types = featureTypes;
2964
                }
2965
            }
2966
            return Collections.unmodifiableList(types);
2967
        } catch (Exception e) {
2968
            throw new GetFeatureTypeException(e, getName());
2969
        }
2970
    }
2971

    
2972
    public List getProviderFeatureTypes() throws DataException {
2973
        return Collections.unmodifiableList(this.featureTypes);
2974
    }
2975

    
2976
    @Override
2977
    public Feature createFeature(FeatureProvider data) throws DataException {
2978
        DefaultFeature feature = new DefaultFeature(this, data);
2979
        return feature;
2980
    }
2981

    
2982
    public Feature createFeature(FeatureProvider data, FeatureType type)
2983
            throws DataException {
2984
        // FIXME: falta por implementar
2985
        // Comprobar si es un subtipo del feature de data
2986
        // y construir un feature usando el subtipo.
2987
        // Probablemente requiera generar una copia del data.
2988
        throw new NotYetImplemented();
2989
    }
2990

    
2991
    @Override
2992
    public EditableFeature createNewFeature(FeatureType type,
2993
            Feature defaultValues) throws DataException {
2994
        try {
2995
            FeatureProvider data = createNewFeatureProvider(type);
2996
            DefaultEditableFeature feature
2997
                    = new DefaultEditableFeature(this, data);
2998
            feature.initializeValues(defaultValues);
2999
            data.setNew(true);
3000

    
3001
            return feature;
3002
        } catch (Exception e) {
3003
            throw new CreateFeatureException(e, getName());
3004
        }
3005
    }
3006

    
3007
    private FeatureProvider createNewFeatureProvider(FeatureType type)
3008
            throws DataException {
3009
        type = this.fixFeatureType((DefaultFeatureType) type);
3010
        FeatureProvider data = this.provider.createFeatureProvider(type);
3011
        data.setNew(true);
3012
        if (type.hasOID() && (data.getOID() == null)) {
3013
            data.setOID(this.provider.createNewOID());
3014
        } else {
3015
            data.setOID(this.getTemporalOID());
3016
        }
3017
        return data;
3018

    
3019
    }
3020

    
3021
    @Override
3022
    public EditableFeature createNewFeature(FeatureType type,
3023
            boolean defaultValues) throws DataException {
3024
        try {
3025
            FeatureProvider data = createNewFeatureProvider(type);
3026
            DefaultEditableFeature feature
3027
                    = new DefaultEditableFeature(this, data);
3028
            if (defaultValues) {
3029
                feature.initializeValues();
3030
            }
3031
            return feature;
3032
        } catch (Exception e) {
3033
            throw new CreateFeatureException(e, getName());
3034
        }
3035
    }
3036

    
3037
    @Override
3038
    public EditableFeature createNewFeature(boolean defaultValues)
3039
            throws DataException {
3040
        return this.createNewFeature(this.getDefaultFeatureType(),
3041
                defaultValues);
3042
    }
3043

    
3044
    @Override
3045
    public EditableFeature createNewFeature() throws DataException {
3046
        return this.createNewFeature(this.getDefaultFeatureType(), true);
3047
    }
3048

    
3049
    @Override
3050
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
3051
        FeatureType ft = this.getDefaultFeatureType();
3052
        EditableFeature f = this.createNewFeature(ft, false);
3053
        f.copyFrom(defaultValues);
3054
        return f;
3055
    }
3056

    
3057
    @Override
3058
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
3059
        FeatureType ft = this.getDefaultFeatureType();
3060
        EditableFeature f = this.createNewFeature(ft, false);
3061
        f.copyFrom(defaultValues);
3062
        return f;
3063
    }
3064

    
3065
    @Override
3066
    public EditableFeatureType createFeatureType() {
3067
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
3068
        return ftype;
3069
    }
3070

    
3071
    @Override
3072
    public EditableFeatureType createFeatureType(String id) {
3073
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
3074
        return ftype;
3075
    }
3076

    
3077
    //
3078
    // ====================================================================
3079
    // Index related methods
3080
    //
3081
    @Override
3082
    public FeatureIndexes getIndexes() {
3083
        return this.indexes;
3084
    }
3085

    
3086
    @Override
3087
    public FeatureIndex createIndex(FeatureType featureType,
3088
            String attributeName, String indexName) throws DataException {
3089
        return createIndex(null, featureType, attributeName, indexName);
3090
    }
3091

    
3092
    @Override
3093
    public FeatureIndex createIndex(String indexTypeName,
3094
            FeatureType featureType, String attributeName, String indexName)
3095
            throws DataException {
3096

    
3097
        return createIndex(indexTypeName, featureType, attributeName,
3098
                indexName, false, null);
3099
    }
3100

    
3101
    @Override
3102
    public FeatureIndex createIndex(FeatureType featureType,
3103
            String attributeName, String indexName, Observer observer)
3104
            throws DataException {
3105
        return createIndex(null, featureType, attributeName, indexName,
3106
                observer);
3107
    }
3108

    
3109
    @Override
3110
    public FeatureIndex createIndex(String indexTypeName,
3111
            FeatureType featureType, String attributeName, String indexName,
3112
            final Observer observer) throws DataException {
3113

    
3114
        return createIndex(indexTypeName, featureType, attributeName,
3115
                indexName, true, observer);
3116
    }
3117

    
3118
    private FeatureIndex createIndex(String indexTypeName,
3119
            FeatureType featureType, String attributeName, String indexName,
3120
            boolean background, final Observer observer) throws DataException {
3121

    
3122
        checkNotInAppendMode();
3123
        FeatureIndexProviderServices index;
3124
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
3125
                featureType, indexName,
3126
                featureType.getAttributeDescriptor(attributeName));
3127

    
3128
        try {
3129
            index.fill(background, observer);
3130
        } catch (FeatureIndexException e) {
3131
            throw new InitializeException(index.getName(), e);
3132
        }
3133

    
3134
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
3135
        return index;
3136
    }
3137

    
3138
    //
3139
    // ====================================================================
3140
    // Transforms related methods
3141
    //
3142
    @Override
3143
    public FeatureStoreTransforms getTransforms() {
3144
        return this.transforms;
3145
    }
3146

    
3147
    @Override
3148
    public FeatureQuery createFeatureQuery() {
3149
        return new DefaultFeatureQuery(this.getName());
3150
    }
3151

    
3152
    @Override
3153
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
3154
        FeatureQuery query = null;
3155
        if ( !ExpressionUtils.isPhraseEmpty(filter) ) {
3156
            query = this.createFeatureQuery();
3157
            query.setFilter(filter);
3158
        }
3159
        if (!StringUtils.isBlank(sortBy)) {
3160
            if (query == null) {
3161
                query = this.createFeatureQuery();
3162
            }
3163
            if (StringUtils.containsAny(sortBy, "(", ")")) {
3164
                throw new IllegalArgumentException("Incorrect sortBy expression");
3165
            }
3166
            String[] attrnames;
3167
            if (sortBy.contains(",")) {
3168
                attrnames = StringUtils.split(sortBy, ",");
3169
            } else {
3170
                attrnames = new String[]{sortBy};
3171
            }
3172
            for (String attrname : attrnames) {
3173
                attrname = attrname.trim();
3174
                if (attrname.startsWith("-")) {
3175
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(1).trim(),'"'), false);
3176
                } else if (attrname.endsWith("-")) {
3177
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(0, sortBy.length() - 1).trim(),'"'), false);
3178
                } else if (attrname.startsWith("+")) {
3179
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(1).trim(),'"'), true);
3180
                } else if (attrname.endsWith("-")) {
3181
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(0, sortBy.length() - 1).trim(),'"'), true);
3182
                } else {
3183
                    query.getOrder().add(StringUtils.unwrap(attrname,'"'), asc);
3184
                }
3185
            }
3186
        }
3187
        if (query != null) {
3188
            query.retrievesAllAttributes();
3189
        }
3190
        return query;
3191
    }
3192

    
3193
    @Override
3194
    public FeatureQuery createFeatureQuery(String filter) {
3195
        return this.createFeatureQuery( 
3196
                ExpressionUtils.createExpression(filter),
3197
                (String) null,
3198
                true
3199
        );
3200
    }
3201

    
3202
    @Override
3203
    public FeatureQuery createFeatureQuery(Expression filter) {
3204
        return this.createFeatureQuery(
3205
                filter,
3206
                (String) null,
3207
                true
3208
        );
3209
    }
3210

    
3211
    @Override
3212
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
3213
        if (StringUtils.isBlank(filter)) {
3214
            return this.createFeatureQuery(
3215
                    (Expression) null,
3216
                    sortBy,
3217
                    asc
3218
            );
3219
        } else {
3220
            return this.createFeatureQuery(
3221
                    ExpressionUtils.createExpression(filter),
3222
                    sortBy,
3223
                    asc
3224
            );
3225
        }
3226
    }
3227

    
3228
    @Override
3229
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
3230
        FeatureQuery query = null;
3231
        if (filter != null) {
3232
            query = this.createFeatureQuery();
3233
            query.setFilter(filter);
3234
        }
3235
        if (sortBy != null) {
3236
            if (query == null) {
3237
                query = this.createFeatureQuery();
3238
            }
3239
            query.getOrder().add(sortBy, asc);
3240
        }
3241

    
3242
        if (query != null) {
3243
            query.retrievesAllAttributes();
3244
        }
3245
        return query;
3246
    }
3247

    
3248
    @Override
3249
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3250
        if (StringUtils.isBlank(filter)) {
3251
            return this.createFeatureQuery(
3252
                    (Expression) null,
3253
                    sortBy,
3254
                    asc
3255
            );
3256
        } else {
3257
            return this.createFeatureQuery(
3258
                    ExpressionUtils.createExpression(filter),
3259
                    sortBy,
3260
                    asc
3261
            );
3262
        }
3263
    }
3264

    
3265
    @Override
3266
    public DataQuery createQuery() {
3267
        return createFeatureQuery();
3268
    }
3269

    
3270
    //
3271
    // ====================================================================
3272
    // UndoRedo related methods
3273
    //
3274
    @Override
3275
    public boolean canRedo() {
3276
        return commands.canRedo();
3277
    }
3278

    
3279
    @Override
3280
    public boolean canUndo() {
3281
        return commands.canUndo();
3282
    }
3283

    
3284
    @Override
3285
    public void redo(int num) throws RedoException {
3286
        for (int i = 0; i < num; i++) {
3287
            redo();
3288
        }
3289
    }
3290

    
3291
    @Override
3292
    public void undo(int num) throws UndoException {
3293
        for (int i = 0; i < num; i++) {
3294
            undo();
3295
        }
3296
    }
3297

    
3298
    //
3299
    // ====================================================================
3300
    // Metadata related methods
3301
    //
3302
    @Override
3303
    public Object getMetadataID() {
3304
        return this.provider.getSourceId();
3305
    }
3306

    
3307
    @Override
3308
    public void delegate(DynObject dynObject) {
3309
        this.metadata.delegate(dynObject);
3310
    }
3311

    
3312
    @Override
3313
    public DynClass getDynClass() {
3314
        return this.metadata.getDynClass();
3315
    }
3316

    
3317
    @Override
3318
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3319
        try {
3320
            if (this.transforms.hasDynValue(name)) {
3321
                return this.transforms.getDynValue(name);
3322
            }
3323
            if (this.metadata.hasDynValue(name)) {
3324
                return this.metadata.getDynValue(name);
3325
            }
3326
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3327
                return this.provider.getProviderName();
3328
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3329
                return this.provider.getSourceId();
3330
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3331
                try {
3332
                    return this.getDefaultFeatureType();
3333
                } catch (DataException e) {
3334
                    return null;
3335
                }
3336
            }
3337
            return this.metadata.getDynValue(name);
3338
        } catch (Exception ex) {
3339
            LOGGER.debug("Can't retrieve the value of '" + name + "' in store '" + this.getName() + "'.", ex);
3340
            return null;
3341
        }
3342
    }
3343

    
3344
    @Override
3345
    public boolean hasDynValue(String name) {
3346
        if (this.transforms.hasDynValue(name)) {
3347
            return true;
3348
        }
3349
        return this.metadata.hasDynValue(name);
3350
    }
3351

    
3352
    @Override
3353
    public boolean hasDynMethod(String name) {
3354
        return ((DynObject_v2) this.metadata).hasDynMethod(name);
3355
    }
3356

    
3357
    @Override
3358
    public void implement(DynClass dynClass) {
3359
        this.metadata.implement(dynClass);
3360
    }
3361

    
3362
    @Override
3363
    public Object invokeDynMethod(String name, Object[] args)
3364
            throws DynMethodException {
3365
        return this.metadata.invokeDynMethod(this, name, args);
3366
    }
3367

    
3368
    @Override
3369
    public Object invokeDynMethod(int code, Object[] args)
3370
            throws DynMethodException {
3371
        return this.metadata.invokeDynMethod(this, code, args);
3372
    }
3373

    
3374
    @Override
3375
    public void setDynValue(String name, Object value)
3376
            throws DynFieldNotFoundException {
3377
        if (this.transforms.hasDynValue(name)) {
3378
            this.transforms.setDynValue(name, value);
3379
            return;
3380
        }
3381
        this.metadata.setDynValue(name, value);
3382

    
3383
    }
3384

    
3385
    /*
3386
     * (non-Javadoc)
3387
     *
3388
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3389
     */
3390
    @Override
3391
    public Set getMetadataChildren() {
3392
        return this.metadataChildren;
3393
    }
3394

    
3395
    /*
3396
     * (non-Javadoc)
3397
     *
3398
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3399
     */
3400
    @Override
3401
    public String getMetadataName() {
3402
        return this.provider.getProviderName();
3403
    }
3404

    
3405
    public FeatureTypeManager getFeatureTypeManager() {
3406
        return this.featureTypeManager;
3407
    }
3408

    
3409
    @Override
3410
    public long getFeatureCount() throws DataException {
3411
        if (featureCount == null) {
3412
            featureCount = this.provider.getFeatureCount();
3413
        }
3414
        if (this.isEditing()) {
3415
            if (this.isAppending()) {
3416
                try {
3417
                    throw new IllegalStateException();
3418
                } catch (IllegalStateException e) {
3419
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND", e);
3420
                }
3421
                return -1;
3422
            } else {
3423
                return featureCount
3424
                        + this.featureManager.getDeltaSize();
3425
            }
3426
        }
3427
        return featureCount;
3428
    }
3429

    
3430
    private Long getTemporalOID() {
3431
        return this.temporalOid++;
3432
    }
3433

    
3434
    @Override
3435
    public FeatureType getProviderFeatureType(String featureTypeId) {
3436
        if (featureTypeId == null) {
3437
            return this.defaultFeatureType;
3438
        }
3439
        FeatureType type;
3440
        Iterator iter = this.featureTypes.iterator();
3441
        while (iter.hasNext()) {
3442
            type = (FeatureType) iter.next();
3443
            if (type.getId().equals(featureTypeId)) {
3444
                return type;
3445
            }
3446
        }
3447
        return null;
3448
    }
3449

    
3450
    @Override
3451
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3452
        return ((DefaultFeature) feature).getData();
3453
    }
3454

    
3455
    @Override
3456
    public DataStore getStore() {
3457
        return this;
3458
    }
3459

    
3460
    @Override
3461
    public FeatureStore getFeatureStore() {
3462
        return this;
3463
    }
3464

    
3465
    @Override
3466
    public void createCache(String name, DynObject parameters)
3467
            throws DataException {
3468
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3469
        if (cache == null) {
3470
            throw new CreateException("FeaureCacheProvider", null);
3471
        }
3472
        cache.apply(this, provider);
3473
        provider = cache;
3474

    
3475
        featureCount = null;
3476
    }
3477

    
3478
    @Override
3479
    public FeatureCache getCache() {
3480
        return cache;
3481
    }
3482

    
3483
    @Override
3484
    public void clear() {
3485
        if (metadata != null) {
3486
            metadata.clear();
3487
        }
3488
    }
3489

    
3490
    @Override
3491
    public String getName() {
3492
        if (this.provider != null) {
3493
            return this.provider.getName();
3494
        }
3495
        if (this.parameters instanceof HasAFile) {
3496
            return FilenameUtils.getName(((HasAFile) this.parameters).getFile().getName());
3497
        }
3498
        return "unknow";
3499
    }
3500

    
3501
    @Override
3502
    public String getFullName() {
3503
        try {
3504
            if (this.provider != null) {
3505
                return this.provider.getFullName();
3506
            }
3507
            if (this.parameters instanceof HasAFile) {
3508
                return (((HasAFile) this.parameters).getFile().getAbsolutePath());
3509
            }
3510
            return null;
3511
        } catch (Throwable th) {
3512
            return null;
3513
        }
3514
    }
3515

    
3516
    @Override
3517
    public String getProviderName() {
3518
        if (this.provider != null) {
3519
            return this.provider.getProviderName();
3520
        }
3521
        if (this.parameters != null) {
3522
            return this.parameters.getDataStoreName();
3523
        }
3524
        return null;
3525

    
3526
    }
3527

    
3528
    @Override
3529
    public boolean isKnownEnvelope() {
3530
        return this.provider.isKnownEnvelope();
3531
    }
3532

    
3533
    @Override
3534
    public boolean hasRetrievedFeaturesLimit() {
3535
        return this.provider.hasRetrievedFeaturesLimit();
3536
    }
3537

    
3538
    @Override
3539
    public int getRetrievedFeaturesLimit() {
3540
        return this.provider.getRetrievedFeaturesLimit();
3541
    }
3542

    
3543
    @Override
3544
    public Interval getInterval() {
3545
        if (this.timeSupport != null) {
3546
            return this.timeSupport.getInterval();
3547
        }
3548
        try {
3549
            FeatureType type = this.getDefaultFeatureType();
3550
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3551
            if (attr != null) {
3552
                Interval interval = attr.getInterval();
3553
                if (interval != null) {
3554
                    return interval;
3555
                }
3556
            }
3557
        } catch (DataException ex) {
3558
        }
3559
        return this.provider.getInterval();
3560
    }
3561

    
3562
    @Override
3563
    public Collection getTimes() {
3564
        if (this.timeSupport != null) {
3565
            return this.timeSupport.getTimes();
3566
        }
3567
        return this.provider.getTimes();
3568
    }
3569

    
3570
    @Override
3571
    public Collection getTimes(Interval interval) {
3572
        if (this.timeSupport != null) {
3573
            return this.timeSupport.getTimes(interval);
3574
        }
3575
        return this.provider.getTimes(interval);
3576
    }
3577

    
3578
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3579
        if (this.isEditing()) {
3580
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' while store is editing.");
3581
        }
3582
        if (!this.transforms.isEmpty()) {
3583
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' if has transforms.");
3584
        }
3585
        FeatureType ft = this.defaultFeatureType;
3586
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3587
        if (attr == null) {
3588
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "', this attribute don't exists.");
3589
        }
3590
        EditableFeatureType eft = ft.getEditable();
3591
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3592
        if (attr != null) {
3593
            if (!(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport)) {
3594
                throw new RuntimeException("Can't add time support, attribute '" + timeSupport.getAttributeName() + "'already exists.");
3595
            }
3596
            eft.remove(attr.getName());
3597
        }
3598
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3599
                timeSupport.getAttributeName(),
3600
                timeSupport.getDataType()
3601
        );
3602
        attrTime.setIsTime(true);
3603
        attrTime.setFeatureAttributeEmulator(timeSupport);
3604
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3605
        this.defaultFeatureType = eft.getNotEditableCopy();
3606

    
3607
        this.timeSupport = timeSupport;
3608
    }
3609

    
3610
    @Override
3611
    @SuppressWarnings("CloneDoesntCallSuperClone")
3612
    public Object clone() throws CloneNotSupportedException {
3613

    
3614
        DataStoreParameters dsp = getParameters();
3615

    
3616
        DefaultFeatureStore cloned_store = null;
3617

    
3618
        try {
3619
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3620
                    openStore(this.getProviderName(), dsp);
3621
            if (transforms != null) {
3622
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3623
                cloned_store.transforms.setStoreForClone(cloned_store);
3624
            }
3625
        } catch (Exception e) {
3626
            throw new CloneException(e);
3627
        }
3628
        return cloned_store;
3629

    
3630
    }
3631

    
3632
    @Override
3633
    public Feature getFeature(DynObject dynobject) {
3634
        if (dynobject instanceof DynObjectFeatureFacade) {
3635
            Feature f = ((DynObjectFeatureFacade) dynobject).getFeature();
3636
            return f;
3637
        }
3638
        return null;
3639
    }
3640

    
3641
    @Override
3642
    public Iterator iterator() {
3643
        FeatureSet fset = null;
3644
        try {
3645
            fset = this.getFeatureSet();
3646
            return fset.fastIterator();
3647
        } catch (DataException ex) {
3648
            throw new RuntimeException(ex);
3649
        } finally {
3650
            DisposeUtils.disposeQuietly(fset);
3651
        }
3652
    }
3653

    
3654
    @Override
3655
    public long size64() {
3656
        FeatureSet fset = null;
3657
        try {
3658
            fset = this.getFeatureSet();
3659
            return fset.getSize();
3660
        } catch (DataException ex) {
3661
            throw new RuntimeException(ex);
3662
        } finally {
3663
            DisposeUtils.disposeQuietly(fset);
3664
        }
3665
    }
3666

    
3667
    @Override
3668
    public ExpressionBuilder createExpressionBuilder() {
3669
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3670
        return builder;
3671
    }
3672

    
3673
    @Override
3674
    public ExpressionBuilder createExpression() {
3675
        return createExpressionBuilder();
3676
    }
3677

    
3678
    public FeatureSet features() throws DataException {
3679
        // This is to avoid jython to create a property with this name
3680
        // to access method getFeatures.
3681
        return this.getFeatureSet();
3682
    }
3683

    
3684
    @Override
3685
    public DataStoreProviderFactory getProviderFactory() {
3686
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3687
        return factory;
3688
    }
3689

    
3690
    @Override
3691
    public void useCache(String providerName, DynObject parameters) throws DataException {
3692
        throw new UnsupportedOperationException();
3693
    }
3694

    
3695
    @Override
3696
    public boolean isBroken() {
3697
        return this.state.isBroken();
3698
    }
3699

    
3700
    @Override
3701
    public Throwable getBreakingsCause() {
3702
        return this.state.getBreakingsCause();
3703
    }
3704

    
3705
    @Override
3706
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3707
        FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3708
        if (!factory.supportNumericOID()) {
3709
            return null;
3710
        }
3711
        SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3712
        return wrappedIndex;
3713
    }
3714

    
3715
    @Override
3716
    public FeatureReference getFeatureReference(String code) {
3717
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3718
        return featureReference;
3719
    }
3720

    
3721
    @Override
3722
    public long getPendingChangesCount() {
3723
        if (this.featureManager == null) {
3724
            return 0;
3725
        }
3726
        return this.featureManager.getPendingChangesCount();
3727
    }
3728

    
3729
    private ResourcesStorage resourcesStorage;
3730

    
3731
    @Override
3732
    public ResourcesStorage getResourcesStorage() {
3733
        if (this.resourcesStorage != null) {
3734
            DisposeUtils.bind(this.resourcesStorage);
3735
            return this.resourcesStorage;
3736
        }
3737
        ResourcesStorage theResourcesStorage;
3738
        try {
3739
            theResourcesStorage = this.provider.getResourcesStorage();
3740
            if (theResourcesStorage != null) {
3741
                this.resourcesStorage = theResourcesStorage;
3742
                DisposeUtils.bind(this.resourcesStorage);
3743
                return theResourcesStorage;
3744
            }
3745
        } catch (Throwable th) {
3746

    
3747
        }
3748
        try {
3749
            DataServerExplorer explorer = this.getExplorer();
3750
            if (explorer == null) {
3751
                return null;
3752
            }
3753
            theResourcesStorage = explorer.getResourcesStorage(this);
3754
            explorer.dispose();
3755
            this.resourcesStorage = theResourcesStorage;
3756
            DisposeUtils.bind(this.resourcesStorage);
3757
            return theResourcesStorage;
3758
        } catch (Exception ex) {
3759
            LOGGER.trace("Can't create resources storage", ex);
3760
            return null;
3761
        }
3762
    }
3763

    
3764
    @Override
3765
    public StoresRepository getStoresRepository() {
3766
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3767
        StoresRepository localRepository = this.provider.getStoresRepository();
3768
        if (localRepository == null) {
3769
            return mainRepository;
3770
        }
3771
        StoresRepository repository = new BaseStoresRepository(this.getName());
3772
        repository.addRepository(localRepository);
3773
        repository.addRepository(mainRepository);
3774
        return repository;
3775
    }
3776

    
3777
    @Override
3778
    public Feature getSampleFeature() {
3779
        if( sampleFeatureCache==null )  {
3780
            this.sampleFeatureCache = new CachedValue<Feature>(sample_feature_cache_timeout_ms) {
3781
                @Override
3782
                protected void reload() {
3783
                    Feature sampleFeature;
3784
                    long t1 = System.currentTimeMillis();
3785
                    try {                        
3786
                        FeatureSelection theSelection = getFeatureSelection();
3787
                        if (theSelection != null && !theSelection.isEmpty()) {
3788
                            sampleFeature = theSelection.first();
3789
                        } else {
3790
                            sampleFeature = first();
3791
                        }
3792
                        if (sampleFeature == null) {
3793
                            sampleFeature = createNewFeature();
3794
                        }
3795
                    } catch (DataException ex) {
3796
                        sampleFeature = null;
3797
                    }
3798
                    long t2 = System.currentTimeMillis();
3799
                    if( (t2 - t1)>5000 ) {
3800
                        // Mas de 5 seg es muy costoso, subimos mucho el tiempo de cache.
3801
                        this.setExpireTime(((60*60)*2)*1000); // 2h
3802
                    }
3803
                    this.setValue(sampleFeature);
3804
                }
3805
            };
3806
        }
3807
        return this.sampleFeatureCache.get();
3808
    }
3809

    
3810
    @Override
3811
    public boolean supportReferences() {
3812
        try {
3813
            return this.getDefaultFeatureType().supportReferences();
3814
        } catch (Exception ex) {
3815
            return false;
3816
        }
3817
    }
3818

    
3819
    private Boolean temporary = null;
3820
    
3821
    @Override
3822
    public boolean isTemporary() {
3823
        if(temporary != null) {
3824
            return this.temporary;
3825
        }
3826
        if (this.provider == null) {
3827
            return true;
3828
        }
3829
        return this.provider.isTemporary();
3830
    }
3831
    
3832
    @Override
3833
    public void setTemporary(Boolean temporary){
3834
        this.temporary = temporary;
3835
    }
3836

    
3837
    public FeatureType getOriginalFeatureType(FeatureType featureType) {
3838
        // FIXME this don't work for Store.fType.size() > 1
3839
        FeatureTypeManager manager = this.featureTypeManager;
3840
        if (manager == null) {
3841
            return null;
3842
        }
3843
        FeatureType originalFeatureType = manager.getOriginalFeatureType();
3844
        if (originalFeatureType == null) {
3845
            return null;
3846
        }
3847
        return originalFeatureType.getCopy();
3848
    }
3849

    
3850
    @Override
3851
    public Object getProperty(String name) {
3852
        if (this.propertiesSupportHelper == null) {
3853
            return null;
3854
        }
3855
        return this.propertiesSupportHelper.getProperty(name);
3856
    }
3857

    
3858
    @Override
3859
    public void setProperty(String name, Object value) {
3860
        if (this.propertiesSupportHelper == null) {
3861
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3862
        }
3863
        this.propertiesSupportHelper.setProperty(name, value);
3864
    }
3865

    
3866
    @Override
3867
    public Map<String, Object> getProperties() {
3868
        if (this.propertiesSupportHelper == null) {
3869
            return Collections.EMPTY_MAP;
3870
        }
3871
        return this.propertiesSupportHelper.getProperties();
3872
    }
3873

    
3874
    @Override
3875
    public Feature getOriginalFeature(FeatureReference id) {
3876
        if (this.featureManager == null) {
3877
            return null;
3878
        }
3879
        return featureManager.getOriginal(id);
3880
    }
3881

    
3882
    @Override
3883
    public Feature getOriginalFeature(Feature feature) {
3884
        if (feature == null) {
3885
            return null;
3886
        }
3887
        return getOriginalFeature(feature.getReference());
3888
    }
3889

    
3890
    @Override
3891
    public boolean isFeatureModified(FeatureReference id) {
3892
        if (this.featureManager == null) {
3893
            return false;
3894
        }
3895
        return featureManager.isFeatureModified(id);
3896
    }
3897

    
3898
    @Override
3899
    public boolean isFeatureModified(Feature feature) {
3900
        if (feature == null) {
3901
            return false;
3902
        }
3903
        return isFeatureModified(feature.getReference());
3904
    }
3905

    
3906
    @Override
3907
    public void setTransaction(DataTransaction transaction) {
3908
        if( this.transaction!=null ) {
3909
            this.transaction.deleteObserver(transactionObserver);
3910
        }
3911
        this.transaction = transaction;
3912
        if (transaction == null || transaction instanceof DataTransactionServices) {
3913
            this.provider.setTransaction((DataTransactionServices) transaction);
3914
        }
3915
        if( transaction!=null ) {
3916
            transaction.addObserver(transactionObserver);
3917
        }
3918
    }
3919

    
3920
    @Override
3921
    public DataTransaction getTransaction() {
3922
        return transaction;
3923
    }
3924

    
3925
    @Override
3926
    public String toString() {
3927
        try {
3928
            return String.format("%s %x %s", this.getClass().getSimpleName(), this.hashCode(), this.getFullName());
3929
        } catch (Exception e) {
3930
            return super.toString();
3931
        }
3932
    }
3933

    
3934
    public String createUniqueID() {
3935
        UUID x = UUID.randomUUID();
3936
        String s = x.toString();
3937
        return s;
3938
    }
3939

    
3940
    @Override
3941
    public List<FeatureReference> getEditedFeatures() {
3942
        if( this.featureManager == null ) {
3943
            return Collections.EMPTY_LIST;
3944
        }
3945
        List<FeatureReference> references = this.featureManager.getAddedAndUpdatedFeatures();
3946
        if( references==null ) {
3947
            return Collections.EMPTY_LIST;
3948
        }
3949
        return references;
3950
    }
3951
    
3952
    public List<FeatureReference> getEditedFeaturesNotValidated() {
3953

    
3954
        try {
3955
            if (this.featureManager == null) {
3956
                return Collections.EMPTY_LIST;
3957
            }
3958
            
3959
            FeatureType type = this.getDefaultFeatureTypeQuietly();
3960
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
3961
            
3962
//            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS | CHECK_BASIC : 0;
3963
            int checks = CHECK_REQUIREDS | CHECK_BASIC;
3964
            if(type.isCheckFeaturesAtFinishEditing()){
3965
                checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
3966
            }
3967
            if (checks == 0) {
3968
                return Collections.EMPTY_LIST;
3969
            }
3970
            List<FeatureReference> references = this.featureManager
3971
                    .getAddedAndUpdatedFeaturesNotValidated(rules, checks);
3972
            if (references == null) {
3973
                return Collections.EMPTY_LIST;
3974
            }
3975
            return references;
3976
        } catch (DataException ex) {
3977
            return null;
3978
        }
3979

    
3980
    }
3981

    
3982
    @Override
3983
    public Iterator<Feature> getFeaturesIterator(Iterator<FeatureReference> references) {
3984
        return new FeatureReferenceIteratorToFeatureIterator(this, references);
3985
    }
3986

    
3987
    @Override
3988
    public Iterable<Feature> getFeaturesIterable(Iterator<FeatureReference> references) {
3989
        return () -> new FeatureReferenceIteratorToFeatureIterator(this, references);
3990
    }
3991

    
3992
    @Override
3993
    public boolean isFeatureSelectionAvailable() {
3994
        try {
3995
            FeatureType type = this.getDefaultFeatureType();
3996
            return type.supportReferences();
3997
        } catch (DataException ex) {
3998
            return false;
3999
        }
4000
    }
4001
}