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

History | View | Annotate | Download (135 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 org.gvsig.fmap.dal.DataQuery;
52
import org.gvsig.fmap.dal.DataServerExplorer;
53
import org.gvsig.fmap.dal.DataSet;
54
import org.gvsig.fmap.dal.DataStore;
55
import org.gvsig.fmap.dal.DataStoreNotification;
56
import org.gvsig.fmap.dal.DataStoreParameters;
57
import org.gvsig.fmap.dal.DataStoreProviderFactory;
58
import org.gvsig.fmap.dal.DataTransaction;
59
import org.gvsig.fmap.dal.StoresRepository;
60
import org.gvsig.fmap.dal.SupportTransactions;
61
import org.gvsig.fmap.dal.exception.CloneException;
62
import org.gvsig.fmap.dal.exception.CloseException;
63
import org.gvsig.fmap.dal.exception.CreateException;
64
import org.gvsig.fmap.dal.exception.DataException;
65
import org.gvsig.fmap.dal.exception.DataRuntimeException;
66
import org.gvsig.fmap.dal.exception.InitializeException;
67
import org.gvsig.fmap.dal.exception.OpenException;
68
import org.gvsig.fmap.dal.exception.ReadException;
69
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
70
import org.gvsig.fmap.dal.exception.WriteException;
71
import org.gvsig.fmap.dal.feature.EditableFeature;
72
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
73
import org.gvsig.fmap.dal.feature.EditableFeatureType;
74
import org.gvsig.fmap.dal.feature.Feature;
75
import static org.gvsig.fmap.dal.feature.Feature.CHECK_BASIC;
76
import static org.gvsig.fmap.dal.feature.Feature.CHECK_REQUIREDS;
77
import static org.gvsig.fmap.dal.feature.Feature.CHECK_RULES_AT_EDITING;
78
import static org.gvsig.fmap.dal.feature.Feature.CHECK_RULES_AT_FINISH;
79
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
80
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
81
import org.gvsig.fmap.dal.feature.FeatureCache;
82
import org.gvsig.fmap.dal.feature.FeatureIndex;
83
import org.gvsig.fmap.dal.feature.FeatureIndexes;
84
import org.gvsig.fmap.dal.feature.FeatureLocks;
85
import org.gvsig.fmap.dal.feature.FeatureQuery;
86
import org.gvsig.fmap.dal.feature.FeatureReference;
87
import org.gvsig.fmap.dal.feature.FeatureReferenceSelection;
88
import org.gvsig.fmap.dal.feature.FeatureSelection;
89
import org.gvsig.fmap.dal.feature.FeatureSet;
90
import org.gvsig.fmap.dal.feature.FeatureSet.DisposableFeatureSetIterable;
91
import org.gvsig.fmap.dal.feature.FeatureStore;
92
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
93
import org.gvsig.fmap.dal.feature.FeatureStoreProviderFactory;
94
import org.gvsig.fmap.dal.feature.FeatureStoreTimeSupport;
95
import org.gvsig.fmap.dal.feature.FeatureStoreTransform;
96
import org.gvsig.fmap.dal.feature.FeatureStoreTransforms;
97
import org.gvsig.fmap.dal.feature.FeatureType;
98
import org.gvsig.fmap.dal.feature.FeatureType.FeatureTypeChanged;
99
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
100
import org.gvsig.fmap.dal.feature.exception.AlreadyEditingException;
101
import org.gvsig.fmap.dal.feature.exception.CreateFeatureException;
102
import org.gvsig.fmap.dal.feature.exception.DataExportException;
103
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
104
import org.gvsig.fmap.dal.feature.exception.FinishEditingException;
105
import org.gvsig.fmap.dal.feature.exception.GetFeatureTypeException;
106
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureException;
107
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureTypeException;
108
import org.gvsig.fmap.dal.feature.exception.NeedEditingModeException;
109
import org.gvsig.fmap.dal.feature.exception.NoNewFeatureInsertException;
110
import org.gvsig.fmap.dal.feature.exception.NullFeatureTypeException;
111
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
112
import org.gvsig.fmap.dal.feature.exception.PersistenceCantFindFeatureTypeException;
113
import org.gvsig.fmap.dal.feature.exception.PersistenceStoreAlreadyLoadedException;
114
import org.gvsig.fmap.dal.feature.exception.SelectionNotAllowedException;
115
import org.gvsig.fmap.dal.feature.exception.StoreCancelEditingException;
116
import org.gvsig.fmap.dal.feature.exception.StoreDeleteEditableFeatureException;
117
import org.gvsig.fmap.dal.feature.exception.StoreDeleteFeatureException;
118
import org.gvsig.fmap.dal.feature.exception.StoreEditException;
119
import org.gvsig.fmap.dal.feature.exception.StoreInsertFeatureException;
120
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureException;
121
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureTypeException;
122
import org.gvsig.fmap.dal.feature.exception.ValidateFeaturesException;
123
import org.gvsig.fmap.dal.feature.exception.WriteNotAllowedException;
124
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
125
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureManager;
126
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureTypeManager;
127
import org.gvsig.fmap.dal.feature.impl.editing.memory.SpatialManager;
128
import org.gvsig.fmap.dal.feature.impl.featurereference.FeatureReferenceFactory;
129
import org.gvsig.fmap.dal.feature.impl.featurereference.FeatureReferenceIteratorToFeatureIterator;
130
import org.gvsig.fmap.dal.feature.impl.featureset.DefaultFeatureSet;
131
import org.gvsig.fmap.dal.feature.impl.undo.DefaultFeatureCommandsStack;
132
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
133
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
134
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
135
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
136
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
137
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
138
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
139
import org.gvsig.fmap.dal.feature.spi.cache.FeatureCacheProvider;
140
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProviderServices;
141
import org.gvsig.fmap.dal.impl.DefaultDataManager;
142
import org.gvsig.fmap.dal.resource.Resource;
143
import org.gvsig.fmap.dal.spi.AbstractDataStore;
144
import org.gvsig.fmap.dal.spi.DataStoreInitializer2;
145
import org.gvsig.fmap.dal.spi.DataStoreProvider;
146
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
147
import org.gvsig.fmap.dal.spi.DataTransactionServices;
148
import org.gvsig.fmap.geom.Geometry;
149
import org.gvsig.fmap.geom.SpatialIndex;
150
import org.gvsig.fmap.geom.primitive.Envelope;
151
import org.gvsig.metadata.MetadataLocator;
152
import org.gvsig.metadata.MetadataManager;
153
import org.gvsig.metadata.exceptions.MetadataException;
154
import org.gvsig.timesupport.Interval;
155
import org.gvsig.tools.ToolsLocator;
156
import org.gvsig.tools.dispose.DisposableIterator;
157
import org.gvsig.tools.dispose.DisposeUtils;
158
import org.gvsig.tools.dynobject.DelegatedDynObject;
159
import org.gvsig.tools.dynobject.DynClass;
160
import org.gvsig.tools.dynobject.DynObject;
161
import org.gvsig.tools.dynobject.DynObjectManager;
162
import org.gvsig.tools.dynobject.DynObject_v2;
163
import org.gvsig.tools.dynobject.DynStruct;
164
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
165
import org.gvsig.tools.dynobject.exception.DynMethodException;
166
import org.gvsig.tools.exception.BaseException;
167
import org.gvsig.tools.exception.NotYetImplemented;
168
import org.gvsig.tools.identitymanagement.SimpleIdentityManager;
169
import org.gvsig.tools.observer.Observable;
170
import org.gvsig.tools.observer.Observer;
171
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
172
import org.gvsig.tools.persistence.PersistenceManager;
173
import org.gvsig.tools.persistence.Persistent;
174
import org.gvsig.tools.persistence.PersistentState;
175
import org.gvsig.tools.persistence.exception.PersistenceException;
176
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
177
import org.gvsig.tools.undo.RedoException;
178
import org.gvsig.tools.undo.UndoException;
179
import org.gvsig.tools.undo.command.Command;
180
import org.gvsig.tools.util.CachedValue;
181
import org.gvsig.tools.util.ChainedIterator;
182
import org.gvsig.tools.util.GetItemWithSizeIsEmptyAndIterator64;
183
import org.gvsig.tools.util.HasAFile;
184
import org.gvsig.tools.util.PropertiesSupportHelper;
185
import org.gvsig.tools.util.UnmodifiableBasicMap;
186
import org.gvsig.tools.visitor.VisitCanceledException;
187
import org.gvsig.tools.visitor.Visitor;
188

    
189
@SuppressWarnings("UseSpecificCatch")
190
public class DefaultFeatureStore extends AbstractDataStore implements
191
        DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore,
192
        SupportTransactions, Observer {
193

    
194
    public static long sample_feature_cache_timeout_ms = 15000;
195
    
196
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
197

    
198
    private DataStoreParameters parameters = null;
199
    private FeatureSelection selection;
200
    private FeatureLocks locks;
201

    
202
    private DelegateWeakReferencingObservable delegateObservable
203
            = new DelegateWeakReferencingObservable(this);
204

    
205
    private FeatureCommandsStack commands;
206

    
207
    /*
208
    TODO: Sustituir estos tres manager por un EditingManager
209
     */
210
    private FeatureTypeManager featureTypeManager;
211
    private FeatureManager featureManager;
212
    private SpatialManager spatialManager;
213

    
214
    private FeatureType defaultFeatureType = null;
215
    private List<FeatureType> featureTypes = new ArrayList<>();
216

    
217
    private int mode = MODE_QUERY;
218
    private long versionOfUpdate = 0;
219
    private boolean hasStrongChanges = true;
220
    private boolean hasInserts = true;
221

    
222
    private DefaultDataManager dataManager = null;
223

    
224
    private FeatureStoreProvider provider = null;
225

    
226
    private DefaultFeatureIndexes indexes;
227

    
228
    private DefaultFeatureStoreTransforms transforms;
229

    
230
    /*friend*/ DelegatedDynObject metadata;
231

    
232
    private Set metadataChildren;
233

    
234
    private Long featureCount = null;
235

    
236
    private long temporalOid = 0;
237

    
238
    private FeatureCacheProvider cache;
239

    
240
    private final StateInformation state;
241

    
242
    private FeatureStoreTimeSupport timeSupport;
243

    
244
    private PropertiesSupportHelper propertiesSupportHelper;
245
    private DataTransaction transaction;
246

    
247
    private String editingSessionCode;
248
    
249
    private CachedValue<Feature> sampleFeatureCache;
250

    
251
    private class StateInformation extends HashMap<Object, Object> {
252

    
253
        private static final long serialVersionUID = 4109026189635185666L;
254

    
255
        private boolean broken;
256
        private Throwable breakingsCause;
257

    
258
        @SuppressWarnings("OverridableMethodCallInConstructor")
259
        public StateInformation() {
260
            this.clear();
261
        }
262

    
263
        @Override
264
        public void clear() {
265
            this.broken = false;
266
            this.breakingsCause = null;
267
            super.clear();
268
        }
269

    
270
        public boolean isBroken() {
271
            return this.broken;
272
        }
273

    
274
        public void broken() {
275
            this.broken = true;
276
        }
277

    
278
        public Throwable getBreakingsCause() {
279
            return this.breakingsCause;
280
        }
281

    
282
        public void setBreakingsCause(Throwable cause) {
283
            if (this.breakingsCause == null) {
284
                this.breakingsCause = cause;
285
            }
286
            this.broken = true;
287
        }
288
    }
289

    
290
    /*
291
     * TODO:
292
     *
293
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
294
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
295
     * featureType al que se le han cambiado las reglas de validacion cuando
296
     * hasStrongChanges=false.
297
     */
298
    public DefaultFeatureStore() {
299
        this.state = new StateInformation();
300
        this.sampleFeatureCache = null;
301
    }
302

    
303
    @Override
304
    protected DataManager getDataManager() {
305
        return this.dataManager;
306
    }
307

    
308
    @Override
309
    public void intialize(DataManager dataManager,
310
            DataStoreParameters parameters) throws InitializeException {
311

    
312
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
313

    
314
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
315
                FeatureStore.METADATA_DEFINITION_NAME,
316
                MetadataManager.METADATA_NAMESPACE
317
        );
318

    
319
        this.dataManager = (DefaultDataManager) dataManager;
320

    
321
        this.parameters = parameters;
322
        this.transforms = new DefaultFeatureStoreTransforms(this);
323
        try {
324
            indexes = new DefaultFeatureIndexes(this);
325
        } catch (DataException e) {
326
            throw new InitializeException(e);
327
        }
328

    
329
    }
330

    
331
    @Override
332
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
333
        this.provider = (FeatureStoreProvider) provider;
334
        this.delegate((DynObject) provider);
335
        this.metadataChildren = new HashSet();
336
        this.metadataChildren.add(provider);
337
        if (!this.ignoreDALResource) {
338
            loadDALFile();
339

    
340
            // Habria que crear un metodo en el proveedor para que de prioidad
341
            // a los parametros frente a lo que se a leido en el fichero dal
342
            // DataStoreProvider arreglalo segun los parametros del usuario
343
            // fixFeatureTypeFromParameters
344
            this.provider.fixFeatureTypeFromParameters();
345
            try {
346
                if (defaultFeatureType != null) {
347
                    FeatureAttributeDescriptor attrGeom = defaultFeatureType.getDefaultGeometryAttribute();
348
                    if (attrGeom != null) {
349
                        DefaultFeatureAttributeDescriptor gattr = (DefaultFeatureAttributeDescriptor) attrGeom;
350
                        IProjection srs = (IProjection) this.getDynValue(METADATA_CRS);
351
                        if (srs != null && srs != gattr.getSRS()) {
352
                            gattr.setSRSForced(srs);
353
                        }
354
                    }
355
                }
356
            } catch (Throwable th) {
357
                LOGGER.warn("Can't patch DAL file", th);
358
            }
359
        }
360
    }
361

    
362
    @Override
363
    public DataStoreParameters getParameters() {
364
        if (this.parameters == null) {
365
            LOGGER.warn("Store parametes are null");
366
        }
367
        return parameters;
368
    }
369

    
370
    @Override
371
    public int getMode() {
372
        return this.mode;
373
    }
374

    
375
    @Override
376
    public DataManager getManager() {
377
        return this.dataManager;
378
    }
379

    
380
    @Override
381
    public UnmodifiableBasicMap<String, DataStore> getChildren() {
382
        UnmodifiableBasicMap<String, DataStore> children = this.provider.getChildren();
383
        if (children == null) {
384
            return UnmodifiableBasicMap.EMPTY_UNMODIFIABLEBASICMAP;
385
        }
386
        return children;
387
    }
388

    
389
    @Override
390
    public FeatureStoreProvider getProvider() {
391
        return this.provider;
392
    }
393

    
394
    public FeatureManager getFeatureManager() {
395
        return this.featureManager;
396
    }
397

    
398
    @Override
399
    public void setFeatureTypes(List types, FeatureType defaultType) {
400
        this.featureTypes = types;
401
        this.defaultFeatureType = defaultType;
402
    }
403

    
404
    public void open() throws OpenException {
405
        if (this.mode != MODE_QUERY) {
406
            // TODO: Se puede hacer un open estando en edicion ?
407
            try {
408
                throw new IllegalStateException();
409
            } catch (Exception ex) {
410
                LOGGER.warn("Opening a store in editing/append mode (" + this.getFullName() + ").", ex);
411
            }
412
        }
413
        if (this.notifyChange(DataStoreNotification.BEFORE_OPEN).isCanceled()) {
414
            return;
415
        }
416
        this.provider.open();
417
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
418
    }
419

    
420
    @Override
421
    public void refresh() throws OpenException, InitializeException {
422
        if (this.mode != MODE_QUERY) {
423
            throw new IllegalStateException();
424
        }
425
        if (this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH).isCanceled()) {
426
            return;
427
        }
428
        if (state.isBroken()) {
429
            this.load(state);
430
        } else {
431
            this.featureCount = null;
432
            this.provider.refresh();
433
        }
434
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
435
    }
436

    
437
    public void close() throws CloseException {
438
        if (this.mode != MODE_QUERY) {
439
            // TODO: Se puede hacer un close estando en edicion ?
440
            try {
441
                throw new IllegalStateException();
442
            } catch (Exception ex) {
443
                LOGGER.warn("Clossing a store in editing/append mode (" + this.getFullName() + ").", ex);
444
            }
445
        }
446
        if (this.notifyChange(DataStoreNotification.BEFORE_CLOSE).isCanceled()) {
447
            return;
448
        }
449
        this.featureCount = null;
450
        this.provider.close();
451
        this.notifyChange(DataStoreNotification.AFTER_CLOSE);
452
    }
453

    
454
    @Override
455
    protected void doDispose() throws BaseException {
456
        if (this.mode != MODE_QUERY) {
457
            // TODO: Se puede hacer un dispose estando en edicion ?
458
            try {
459
                throw new IllegalStateException();
460
            } catch (Exception ex) {
461
                LOGGER.warn("Dispossing a store in editing/append mode (" + this.getFullName() + ").", ex);
462
            }
463
        }
464
        if (this.notifyChange(DataStoreNotification.BEFORE_DISPOSE).isCanceled()) {
465
            return;
466
        }
467
        this.disposeIndexes();
468
        if (this.provider != null) {
469
            this.provider.dispose();
470
        }
471
        if (this.selection != null) {
472
            this.selection.dispose();
473
            this.selection = null;
474
        }
475
        this.commands = null;
476
        this.featureCount = null;
477
        if (this.locks != null) {
478
            // this.locks.dispose();
479
            this.locks = null;
480
        }
481

    
482
        if (this.featureTypeManager != null) {
483
            this.featureTypeManager.dispose();
484
            this.featureTypeManager = null;
485
        }
486

    
487
        this.featureManager = null;
488
        this.spatialManager = null;
489

    
490
        this.parameters = null;
491
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
492
        if (delegateObservable != null) {
493
            this.delegateObservable.deleteObservers();
494
            this.delegateObservable = null;
495
        }
496
    }
497

    
498
    @Override
499
    public boolean allowWrite() {
500
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
501
        if (!identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION, this.getParameters(), this.getName())) {
502
            return false;
503
        }
504
        return this.provider.allowWrite();
505
    }
506

    
507
    @Override
508
    public boolean canWriteGeometry(int geometryType) throws DataException {
509
        return this.provider.canWriteGeometry(geometryType, 0);
510
    }
511

    
512
    @Override
513
    public DataServerExplorer getExplorer() throws ReadException,
514
            ValidateDataParametersException {
515
        if (this.state.isBroken()) {
516
            try {
517
                return this.provider.getExplorer();
518
            } catch (Throwable th) {
519
                return null;
520
            }
521
        } else {
522
            return this.provider.getExplorer();
523
        }
524
    }
525

    
526
    /*
527
     * public Metadata getMetadata() throws MetadataNotFoundException {
528
     * // TODO:
529
     * // Si el provider devuelbe null habria que ver de construir aqui
530
     * // los metadatos basicos, como el Envelope y el SRS.
531
     *
532
     * // TODO: Estando en edicion el Envelope deberia de
533
     * // actualizarse usando el spatialManager
534
     * return this.provider.getMetadata();
535
     * }
536
     */
537
    @Override
538
    public Envelope getEnvelope() throws DataException {
539
        if (this.mode == MODE_FULLEDIT) {
540
            // Just in case another thread tries to write in the store
541
            synchronized (this) {
542
                return this.spatialManager.getEnvelope();
543
            }
544
        }
545
        if (hasDynValue(DataStore.METADATA_ENVELOPE)) {
546
            return (Envelope) getDynValue(DataStore.METADATA_ENVELOPE);
547
        }
548
        Envelope envelope = this.provider.getEnvelope();
549
        if (envelope != null) {
550
            return envelope;
551
        }
552
        FeatureAttributeDescriptor attrdesc = this.getDefaultFeatureType().getDefaultGeometryAttribute();
553
        if (attrdesc == null || !attrdesc.isComputed()) {
554
            return null;
555
        }
556
        final int index = attrdesc.getIndex();
557
        final MutableObject<Envelope> envelopeValue = new MutableObject<>();
558
        try {
559
            this.accept((Object obj) -> {
560
                Feature f = (Feature) obj;
561
                Geometry g = (Geometry) f.get(index);
562
                if (g == null) {
563
                    return;
564
                }
565
                if (envelopeValue.getValue() == null) {
566
                    envelopeValue.setValue(g.getEnvelope());
567
                } else {
568
                    envelopeValue.getValue().add(g);
569
                }
570
            });
571
        } catch (Throwable th) {
572
            LOGGER.warn("Can't calculate envelope", th);
573
            return null;
574
        }
575
        return envelopeValue.getValue();
576
    }
577

    
578
    /**
579
     * @throws org.gvsig.fmap.dal.exception.DataException
580
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
581
     */
582
    @Override
583
    public IProjection getSRSDefaultGeometry() throws DataException {
584
        return this.getDefaultFeatureType().getDefaultSRS();
585
    }
586

    
587
    @Override
588
    public FeatureSelection createDefaultFeatureSelection()
589
            throws DataException {
590
        return new DefaultFeatureSelection(this);
591
    }
592

    
593
    @Override
594
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
595
            throws DataException {
596
        if (type.hasOID()) {
597
            return new DefaultFeatureProvider(type,
598
                    this.provider.createNewOID());
599
        }
600
        return new DefaultFeatureProvider(type);
601
    }
602

    
603
    @Override
604
    public void saveToState(PersistentState state) throws PersistenceException {
605
        /*if (this.mode != FeatureStore.MODE_QUERY) {
606
            throw new PersistenceException(new IllegalStateException(
607
                this.getName()));
608
        }*/
609
        state.set("dataStoreName", this.getName());
610
        state.set("parameters", this.parameters);
611
        state.set("selection", this.selection);
612
        state.set("transforms", this.transforms);
613
        // TODO locks persistence
614
        // state.set("locks", this.locks);
615
        // TODO indexes persistence
616
        // state.set("indexes", this.indexes);
617
        Map evaluatedAttr = new HashMap(1);
618
        Iterator iterType = featureTypes.iterator();
619
        Iterator iterAttr;
620
        FeatureType type;
621
        DefaultFeatureAttributeDescriptor attr;
622
        List attrs;
623
        while (iterType.hasNext()) {
624
            type = (FeatureType) iterType.next();
625
            attrs = new ArrayList();
626
            iterAttr = type.iterator();
627
            while (iterAttr.hasNext()) {
628
                attr = (DefaultFeatureAttributeDescriptor) iterAttr.next();
629
                if ((attr.getEvaluator() != null)
630
                        && (attr.getEvaluator() instanceof Persistent)) {
631
                    attrs.add(attr);
632
                }
633
            }
634
            if (!attrs.isEmpty()) {
635
                evaluatedAttr.put(type.getId(), attrs);
636
            }
637

    
638
        }
639

    
640
        if (evaluatedAttr.isEmpty()) {
641
            evaluatedAttr = null;
642
        }
643

    
644
        state.set("evaluatedAttributes", evaluatedAttr);
645
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
646

    
647
    }
648

    
649
    @Override
650
    public void loadFromState(final PersistentState persistentState)
651
            throws PersistenceException {
652
        if (this.provider != null) {
653
            throw new PersistenceStoreAlreadyLoadedException(this.getName());
654
        }
655
        if (this.getManager() == null) {
656
            this.dataManager = (DefaultDataManager) DALLocator.getDataManager();
657
        }
658
        state.clear();
659
        try {
660
            state.put("parameters", persistentState.get("parameters"));
661
        } catch (Throwable th) {
662
            state.setBreakingsCause(th);
663
        }
664
        try {
665
            state.put("selection", persistentState.get("selection"));
666
        } catch (Throwable th) {
667
            state.setBreakingsCause(th);
668
        }
669
        try {
670
            state.put("transforms", persistentState.get("transforms"));
671
        } catch (Throwable th) {
672
            state.setBreakingsCause(th);
673
        }
674
        try {
675
            state.put("evaluatedAttributes", persistentState.get("evaluatedAttributes"));
676
        } catch (Throwable th) {
677
            state.setBreakingsCause(th);
678
        }
679
        try {
680
            state.put("defaultFeatureTypeId", persistentState.getString("defaultFeatureTypeId"));
681
        } catch (Throwable th) {
682
            state.setBreakingsCause(th);
683
        }
684
        load(state);
685
        ((DefaultDataManager) this.getDataManager()).addObservers(this);
686
    }
687

    
688
    private void load(StateInformation state) {
689
        this.featureTypes = new ArrayList();
690
        this.defaultFeatureType = null;
691
        this.featureCount = null;
692

    
693
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
694
        try {
695
            intialize(dataManager, params);
696
        } catch (Throwable th) {
697
            state.setBreakingsCause(th);
698
        }
699

    
700
        try {
701
            DataStoreProvider prov = dataManager.createProvider(
702
                    getStoreProviderServices(),
703
                    params
704
            );
705
            setProvider(prov);
706
        } catch (Throwable th) {
707
            LOGGER.warn("Can't load store from state.", th);
708
            state.setBreakingsCause(th);
709
        }
710
        try {
711
            selection = (FeatureSelection) state.get("selection");
712
        } catch (Throwable th) {
713
            state.setBreakingsCause(th);
714
        }
715

    
716
        try {
717
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
718
            this.transforms.setFeatureStore(this);
719
            for (FeatureStoreTransform transform : this.transforms) {
720
                try {
721
                    transform.setUp();
722
                } catch (Throwable th) {
723
                    state.setBreakingsCause(th);
724
                }
725
            }
726
        } catch (Throwable th) {
727
            state.setBreakingsCause(th);
728
        }
729

    
730
        try {
731
            Map evaluatedAttributes = (Map) state.get("evaluatedAttributes");
732
            if ((evaluatedAttributes != null) && !evaluatedAttributes.isEmpty()) {
733
                Iterator iterEntries = evaluatedAttributes.entrySet().iterator();
734
                while (iterEntries.hasNext()) {
735
                    Entry entry = (Entry) iterEntries.next();
736
                    List attrs = (List) entry.getValue();
737
                    if (attrs.isEmpty()) {
738
                        continue;
739
                    }
740
                    int fTypePos = -1;
741
                    DefaultFeatureType type = null;
742
                    for (int i = 0; i < featureTypes.size(); i++) {
743
                        type = (DefaultFeatureType) featureTypes.get(i);
744
                        if (type.getId().equals(entry.getKey())) {
745
                            fTypePos = i;
746
                            break;
747
                        }
748
                    }
749
                    if (type == null) {
750
                        throw new PersistenceCantFindFeatureTypeException(
751
                                getName(), (String) entry.getKey());
752
                    }
753
                    DefaultEditableFeatureType eType = (DefaultEditableFeatureType) type.getEditable();
754
                    Iterator<FeatureAttributeDescriptor> iterAttr = attrs.iterator();
755
                    while (iterAttr.hasNext()) {
756
                        FeatureAttributeDescriptor attr = iterAttr.next();
757
                        eType.addLike(attr);
758
                    }
759
                    featureTypes.set(fTypePos, eType.getNotEditableCopy());
760

    
761
                }
762

    
763
            }
764
        } catch (Throwable th) {
765
            state.setBreakingsCause(th);
766
        }
767

    
768
        try {
769
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
770
            FeatureType ftype;
771

    
772
            if (defaultFeatureType == null
773
                    || defaultFeatureType.getId() == null
774
                    || !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
775

    
776
                ftype = getFeatureType(defaultFeatureTypeId);
777
                if (ftype == null) {
778
                    /*
779
                             * Un error en el m?todo de PostgreSQL getName(), hace que
780
                             * el nombre del featureType sea valor retornado por el getProviderName()
781
                             * De momento se pone este parche para apa?arlo y poder mantener compatibilidad
782
                             * con proyectos antiguos (2.1 y 2.2)
783
                     */
784
                    ftype = getFeatureType(getName());
785
                    if (ftype == null) {
786
                        throw new RuntimeException("Can't locate feature type");
787
                    }
788
                }
789
                defaultFeatureType = ftype;
790
            }
791
        } catch (Throwable th) {
792
            state.setBreakingsCause(th);
793
        }
794

    
795
        LOGGER.debug("load() broken:{}, {}, {}.",
796
                new Object[]{state.isBroken(), this.getProviderName(), params}
797
        );
798
    }
799

    
800
    public DataStoreProviderServices getStoreProviderServices() {
801
        return this;
802
    }
803

    
804
    public static void registerPersistenceDefinition() {
805
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
806
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
807
            DynStruct definition
808
                    = manager.addDefinition(DefaultFeatureStore.class,
809
                            PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
810
                            + " Persistent definition", null, null);
811
            definition.addDynFieldString("dataStoreName").setMandatory(true)
812
                    .setPersistent(true);
813

    
814
            definition.addDynFieldObject("parameters")
815
                    .setClassOfValue(DynObject.class).setMandatory(true)
816
                    .setPersistent(true);
817

    
818
            definition.addDynFieldObject("selection")
819
                    .setClassOfValue(FeatureSelection.class).setMandatory(false)
820
                    .setPersistent(true);
821

    
822
            definition.addDynFieldObject("transforms")
823
                    .setClassOfValue(DefaultFeatureStoreTransforms.class)
824
                    .setMandatory(true).setPersistent(true);
825

    
826
            definition.addDynFieldMap("evaluatedAttributes")
827
                    .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
828
                    .setMandatory(false).setPersistent(true);
829

    
830
            definition.addDynFieldString("defaultFeatureTypeId")
831
                    .setMandatory(true).setPersistent(true);
832
        }
833
    }
834

    
835
    public static void registerMetadataDefinition() throws MetadataException {
836
        MetadataManager manager = MetadataLocator.getMetadataManager();
837
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
838
            DynStruct metadataDefinition
839
                    = manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
840
            metadataDefinition.extend(manager
841
                    .getDefinition(DataStore.METADATA_DEFINITION_NAME));
842
        }
843
    }
844

    
845
    //
846
    // ====================================================================
847
    // Gestion de la seleccion
848
    //
849
    @Override
850
    public void setSelection(DataSet selection) throws DataException {
851
        this.setSelection((FeatureSet) selection);
852
    }
853

    
854
    @Override
855
    public DataSet createSelection() throws DataException {
856
        return createFeatureSelection();
857
    }
858

    
859
    @Override
860
    public DataSet getSelection() throws DataException {
861
        return this.getFeatureSelection();
862
    }
863

    
864
    @Override
865
    public void setSelection(FeatureSet selection) throws DataException {
866
        setSelection(selection, true);
867
    }
868

    
869
    public void setSelection(FeatureSet selection, boolean undoable)
870
            throws DataException {
871
        if (selection == null) {
872
            if (undoable) {
873
                throw new SelectionNotAllowedException(getName());
874
            }
875

    
876
        } else {
877
            if (selection.equals(this.selection)) {
878
                return;
879
            }
880
            if (!selection.isFromStore(this)) {
881
                throw new SelectionNotAllowedException(getName());
882
            }
883
        }
884

    
885
        if (this.selection != null) {
886
            this.selection.deleteObserver(this);
887
        }
888
        if (selection == null) {
889
            if (this.selection != null) {
890
                this.selection.dispose();
891
            }
892
            this.selection = null;
893
            return;
894
        }
895
        if (selection instanceof FeatureSelection) {
896
            if (undoable && isEditing()) {
897
                commands.selectionSet(this, this.selection,
898
                        (FeatureSelection) selection);
899
            }
900
            if (this.selection != null) {
901
                this.selection.dispose();
902
            }
903
            this.selection = (FeatureSelection) selection;
904
        } else {
905
            if (undoable && isEditing()) {
906
                commands.startComplex("_selectionSet");
907
            }
908
            if (selection instanceof DefaultFeatureSelection) {
909
                DefaultFeatureSelection defSelection
910
                        = (DefaultFeatureSelection) selection;
911
                defSelection.deselectAll(undoable);
912
                defSelection.select(selection, undoable);
913
            } else {
914
                this.selection.deselectAll();
915
                this.selection.select(selection);
916
            }
917
            if (undoable && isEditing()) {
918
                commands.endComplex();
919
            }
920
        }
921
        this.selection.addObserver(this);
922

    
923
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
924
    }
925

    
926
    @Override
927
    public FeatureSelection createFeatureSelection() throws DataException {
928
        long maxSize = dataManager.getMaxSizeForSmallFeatureSelection();
929
        if (this.provider.getFeatureCount() > maxSize) {
930
            return createLargeFeatureSelection();
931
        }
932
        return this.provider.createFeatureSelection();
933
    }
934

    
935
    @Override
936
    public FeatureSelection createLargeFeatureSelection() throws DataException {
937
        return new LargeFeatureSelection(this);
938

    
939
    }
940

    
941
    @Override
942
    public FeatureSelection createMemoryFeatureSelection() throws DataException {
943
        return this.provider.createFeatureSelection();
944
    }
945

    
946
    @Override
947
    public FeatureSelection getFeatureSelection() throws DataException {
948
        if (selection == null) {
949
            this.selection = createFeatureSelection();
950
            this.selection.addObserver(this);
951
        }
952
        return selection;
953
    }
954

    
955
    @Override
956
    public boolean isFeatureSelectionEmpty() {
957
        if( selection == null ) {
958
            return true;
959
        }
960
        return selection.isEmpty();
961
    }
962
    
963
    //
964
    // ====================================================================
965
    // Gestion de notificaciones
966
    //
967
    @Override
968
    public FeatureStoreNotification notifyChange(FeatureStoreNotification storeNotification) {
969
        if (delegateObservable != null) {
970
            try {
971
                delegateObservable.notifyObservers(storeNotification);
972
            } catch (Throwable ex) {
973
                LOGGER.warn("Problems notifying changes in the store '" + this.getName() + " (" + storeNotification.getType() + ").", ex);
974
            }
975
        }
976
        return storeNotification;
977
    }
978

    
979
    @Override
980
    public FeatureStoreNotification notifyChange(String notification) {
981
        return notifyChange(new DefaultFeatureStoreNotification(this, notification));
982
    }
983

    
984
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode) {
985
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode));
986
    }
987

    
988
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode, int editMode) {
989
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode, editMode));
990
    }
991

    
992
    public FeatureStoreNotification notifyChange(String notification,
993
            String editingSessionCode,
994
            Iterator<FeatureReference> deleteds,
995
            Iterator<EditableFeature> inserteds,
996
            Iterator<EditableFeature> updateds,
997
            Iterator<FeatureTypeChanged> featureTypesChanged,
998
            boolean isSelectionCompromised) {
999
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode,
1000
                deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised));
1001
    }
1002

    
1003
    @Override
1004
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
1005
        Feature f = null;
1006
        if (data != null) {
1007
            try {
1008
                f = createFeature(data);
1009
            } catch (Throwable ex) {
1010
                LOGGER.warn("Problems creating a feature to notifying changes in the store '" + this.getName() + " (" + notification + ").", ex);
1011
            }
1012
        }
1013
        return notifyChange(notification, f);
1014
    }
1015

    
1016
    public FeatureStoreNotification notifyChange(String notification, Feature feature) {
1017
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
1018
                feature));
1019
    }
1020

    
1021
    public FeatureStoreNotification notifyChange(String notification, Command command) {
1022
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
1023
                command));
1024
    }
1025

    
1026
    public FeatureStoreNotification notifyChange(String notification, EditableFeatureType type) {
1027
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
1028
                type));
1029
    }
1030

    
1031
    @Override
1032
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
1033
        return notifyChange(new DefaultFeatureStoreNotification(this,
1034
                DataStoreNotification.RESOURCE_CHANGED));
1035
    }
1036

    
1037
    //
1038
    // ====================================================================
1039
    // Gestion de bloqueos
1040
    //
1041
    @Override
1042
    public boolean isLocksSupported() {
1043
        return this.provider.isLocksSupported();
1044
    }
1045

    
1046
    @Override
1047
    public FeatureLocks getLocks() throws DataException {
1048
        if (!this.provider.isLocksSupported()) {
1049
            LOGGER.warn("Locks not supported");
1050
            return null;
1051
        }
1052
        if (locks == null) {
1053
            this.locks = this.provider.createFeatureLocks();
1054
        }
1055
        return locks;
1056
    }
1057

    
1058
    //
1059
    // ====================================================================
1060
    // Interface Observable
1061
    //
1062
    @Override
1063
    public void disableNotifications() {
1064
        this.delegateObservable.disableNotifications();
1065

    
1066
    }
1067

    
1068
    @Override
1069
    public void enableNotifications() {
1070
        this.delegateObservable.enableNotifications();
1071
    }
1072

    
1073
    @Override
1074
    public void beginComplexNotification() {
1075
        this.delegateObservable.beginComplexNotification();
1076

    
1077
    }
1078

    
1079
    @Override
1080
    public void endComplexNotification() {
1081
        this.delegateObservable.endComplexNotification();
1082

    
1083
    }
1084

    
1085
    @Override
1086
    public void addObserver(Observer observer) {
1087
        if (delegateObservable != null) {
1088
            this.delegateObservable.addObserver(observer);
1089
        }
1090
    }
1091

    
1092
    @Override
1093
    public void deleteObserver(Observer observer) {
1094
        if (delegateObservable != null) {
1095
            this.delegateObservable.deleteObserver(observer);
1096
        }
1097
    }
1098

    
1099
    @Override
1100
    public void deleteObservers() {
1101
        this.delegateObservable.deleteObservers();
1102

    
1103
    }
1104

    
1105
    //
1106
    // ====================================================================
1107
    // Interface Observer
1108
    //
1109
    // Usado para observar:
1110
    // - su seleccion
1111
    // - sus bloqueos
1112
    // - sus recursos
1113
    //
1114
    @Override
1115
    public void update(Observable observable, Object notification) {
1116
        if (observable instanceof FeatureSet) {
1117
            if (observable == this.selection) {
1118
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1119
            } else if (observable == this.locks) {
1120
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1121
            }
1122

    
1123
        } else if (observable instanceof FeatureStoreProvider) {
1124
            if (observable == this.provider) {
1125

    
1126
            }
1127
        } else if (observable instanceof FeatureReferenceSelection) {
1128
            if (notification instanceof String) {
1129
                this.notifyChange((String) notification);
1130
            }
1131
        }
1132
    }
1133

    
1134
    //
1135
    // ====================================================================
1136
    // Edicion
1137
    //
1138
    private void newVersionOfUpdate() {
1139
        this.versionOfUpdate++;
1140
    }
1141

    
1142
    private long currentVersionOfUpdate() {
1143
        return this.versionOfUpdate;
1144
    }
1145

    
1146
    private void checkInEditingMode() throws NeedEditingModeException {
1147
        if (mode != MODE_FULLEDIT) {
1148
            throw new NeedEditingModeException(this.getName());
1149
        }
1150
    }
1151

    
1152
    private void checkNotInAppendMode() throws IllegalStateException {
1153
        if (mode == MODE_APPEND) {
1154
            throw new IllegalStateException("Error: store "
1155
                    + this.getFullName() + " is in append mode");
1156
        }
1157
    }
1158

    
1159
    private void checkIsOwnFeature(Feature feature)
1160
            throws IllegalFeatureException {
1161
        if (((DefaultFeature) feature).getStore() != this) {
1162
            throw new IllegalFeatureException(this.getName());
1163
        }
1164
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1165
        // fixFeatureType((DefaultFeatureType) feature.getType());
1166
    }
1167

    
1168
    private void exitEditingMode() {
1169
        if (commands != null) {
1170
            try {
1171
                commands.clear();
1172
            } catch (Exception ex) {
1173
                LOGGER.trace("Can't clear commands", ex);
1174
            }
1175
            commands = null;
1176
        }
1177

    
1178
        if (featureTypeManager != null) {
1179
            DisposeUtils.disposeQuietly(featureTypeManager);
1180
            featureTypeManager = null;
1181

    
1182
        }
1183

    
1184
        // TODO implementar un dispose para estos dos
1185
        featureManager = null;
1186
        spatialManager = null;
1187

    
1188
        featureCount = null;
1189

    
1190
        mode = MODE_QUERY;
1191
        hasStrongChanges = true; // Lo deja a true por si las moscas
1192
        hasInserts = true;
1193

    
1194
        this.editingSessionCode = null;
1195
    }
1196

    
1197
    @Override
1198
    synchronized public void edit() throws DataException {
1199
        edit(MODE_FULLEDIT);
1200
    }
1201

    
1202
    @Override
1203
    synchronized public void edit(int mode) throws DataException {
1204
        LOGGER.debug("Starting editing in mode: {}", mode);
1205
        String newSessionCode = this.createUniqueID();
1206
        try {
1207
            if (this.mode != MODE_QUERY) {
1208
                throw new AlreadyEditingException(this.getName());
1209
            }
1210
            if (!this.provider.supportsAppendMode()) {
1211
                mode = MODE_FULLEDIT;
1212
            }
1213
            switch (mode) {
1214
                case MODE_QUERY:
1215
                    throw new IllegalStateException(this.getName());
1216

    
1217
                case MODE_FULLEDIT:
1218
                    if (!this.transforms.isEmpty()) {
1219
                        throw new IllegalStateException(this.getName());
1220
                    }
1221
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1222
                            newSessionCode, mode).isCanceled()) {
1223
                        return;
1224
                    }
1225
                    this.editingSessionCode = newSessionCode;
1226
                    invalidateIndexes();
1227
                    featureManager = new FeatureManager(this);
1228
                    featureTypeManager = new FeatureTypeManager(this);
1229
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
1230

    
1231
                    commands = new DefaultFeatureCommandsStack(
1232
                            this, featureManager,
1233
                            spatialManager, featureTypeManager);
1234
                    this.mode = MODE_FULLEDIT;
1235
                    hasStrongChanges = false;
1236
                    hasInserts = false;
1237
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING, newSessionCode, this.mode);
1238
                    break;
1239

    
1240
                case MODE_APPEND:
1241
                    if (!this.transforms.isEmpty()) {
1242
                        throw new IllegalStateException(this.getName());
1243
                    }
1244
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1245
                            newSessionCode, mode).isCanceled()) {
1246
                        return;
1247
                    }
1248
                    this.editingSessionCode = newSessionCode;
1249
                    invalidateIndexes();
1250
                    this.provider.beginAppend();
1251
                    this.mode = MODE_APPEND;
1252
                    hasInserts = false;
1253
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1254
                            newSessionCode, this.mode);
1255
                    break;
1256
                case MODE_PASS_THROUGH:
1257
                    if (!this.provider.supportsPassThroughMode()) {
1258
                        throw new IllegalStateException(this.getName());
1259
                    }
1260
                    if (!this.transforms.isEmpty()) {
1261
                        throw new IllegalStateException(this.getName());
1262
                    }
1263
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1264
                            newSessionCode, mode).isCanceled()) {
1265
                        return;
1266
                    }
1267
                    this.editingSessionCode = newSessionCode;
1268
                    invalidateIndexes();
1269
                    this.mode = MODE_PASS_THROUGH;
1270
                    hasInserts = false;
1271
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1272
                            newSessionCode, this.mode);
1273
                    break;
1274

    
1275
            }
1276
        } catch (Exception e) {
1277
            try {
1278
                if (this.mode != MODE_QUERY) {
1279
                    exitEditingMode();
1280
                }
1281
                notifyChange(FeatureStoreNotification.FAILED_STARTEDITING,
1282
                        newSessionCode, mode);
1283
            } catch (Throwable th) {
1284
                LOGGER.warn("Can't cleanup after error in start editing.", th);
1285
            }
1286
            throw new StoreEditException(e, this.getName());
1287
        }
1288
    }
1289

    
1290
    private void invalidateIndexes() {
1291
        setIndexesValidStatus(false);
1292
    }
1293

    
1294
    private void setIndexesValidStatus(boolean valid) {
1295
        FeatureIndexes theIndexes = getIndexes();
1296
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1297
                ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1298
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1299
            FeatureIndex index = (FeatureIndex) iterator.next();
1300
            if (index instanceof FeatureIndexProviderServices) {
1301
                FeatureIndexProviderServices indexServices
1302
                        = (FeatureIndexProviderServices) index;
1303
                indexServices.setValid(valid);
1304
            }
1305
        }
1306
    }
1307

    
1308
    private void updateIndexes() throws FeatureIndexException {
1309
        FeatureIndexes theIndexes = getIndexes();
1310
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1311
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1312
            FeatureIndex index = (FeatureIndex) iterator.next();
1313
            if (index instanceof FeatureIndexProviderServices) {
1314
                FeatureIndexProviderServices indexServices
1315
                        = (FeatureIndexProviderServices) index;
1316
                indexServices.fill(true, null);
1317
            }
1318
        }
1319
    }
1320

    
1321
    private void waitForIndexes() {
1322
        FeatureIndexes theIndexes = getIndexes();
1323
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1324
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1325
            FeatureIndex index = (FeatureIndex) iterator.next();
1326
            if (index instanceof FeatureIndexProviderServices) {
1327
                FeatureIndexProviderServices indexServices
1328
                        = (FeatureIndexProviderServices) index;
1329
                indexServices.waitForIndex();
1330
            }
1331
        }
1332
    }
1333

    
1334
    private void disposeIndexes() {
1335
        FeatureIndexes theIndexes = getIndexes();
1336
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1337
        if (theIndexes == null) {
1338
            return;
1339
        }
1340
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1341
            FeatureIndex index = (FeatureIndex) iterator.next();
1342
            if (index instanceof FeatureIndexProviderServices) {
1343
                FeatureIndexProviderServices indexServices
1344
                        = (FeatureIndexProviderServices) index;
1345
                indexServices.dispose();
1346
            }
1347
        }
1348
    }
1349

    
1350
    @Override
1351
    public boolean isEditing() {
1352
        return mode == MODE_FULLEDIT;
1353
    }
1354

    
1355
    @Override
1356
    public boolean isAppending() {
1357
        return mode == MODE_APPEND;
1358
    }
1359

    
1360
    @Override
1361
    synchronized public void update(EditableFeatureType type)
1362
            throws DataException {
1363
        try {
1364
            if (type == null) {
1365
                throw new NullFeatureTypeException(getName());
1366
            }
1367

    
1368
            switch (this.mode) {
1369
                case MODE_QUERY:
1370
                    if (type.hasOnlyMetadataChanges(this.defaultFeatureType)) {
1371
                        if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1372
                            return;
1373
                        }
1374
                        FeatureType theType = type.getNotEditableCopy();
1375
                        if (defaultFeatureType.getId().equals(theType.getId())) {
1376
                            defaultFeatureType = theType;
1377
                        }
1378
                        List newtypes = new ArrayList();
1379
                        for (FeatureType featureType : this.featureTypes) {
1380
                            if (featureType.getId().equals(theType.getId())) {
1381
                                newtypes.add(theType);
1382
                            } else {
1383
                                newtypes.add(featureType);
1384
                            }
1385
                        }
1386
                        this.featureTypes = newtypes;
1387
                        saveDALFile();
1388
                        notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1389
                    }
1390

    
1391
                    break;
1392
                case MODE_FULLEDIT:
1393
                    if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1394
                        return;
1395
                    }
1396
                    newVersionOfUpdate();
1397

    
1398
                    FeatureType oldt = type.getSource().getCopy();
1399
                    FeatureType newt = type.getCopy();
1400
                    commands.update(newt, oldt);
1401
                    hasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1402
                    notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1403
                    break;
1404
                case MODE_APPEND:
1405
                case MODE_PASS_THROUGH:
1406
                    throw new NeedEditingModeException(this.getName());
1407

    
1408
            }
1409
        } catch (Exception e) {
1410
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1411
        }
1412
    }
1413

    
1414
    @Override
1415
    public void delete(Feature feature) throws DataException {
1416
        switch (this.mode) {
1417
            case MODE_PASS_THROUGH:
1418
                checkIsOwnFeature(feature);
1419
                if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1420
                    return;
1421
                }
1422
                this.provider.passThroughDelete((FeatureReferenceProviderServices) feature.getReference());
1423
                notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1424
                break;
1425
            default:
1426
                this.commands.delete(feature);
1427
                break;
1428

    
1429
        }
1430
    }
1431

    
1432
    @Override
1433
    public void delete(String filter) {
1434
        if (StringUtils.isBlank(filter)) {
1435
            return;
1436
        }
1437
        this.delete(ExpressionUtils.createExpression(filter));
1438
    }
1439

    
1440
    @Override
1441
    public void delete(Expression filter) {
1442
        // TODO: Optimizar pasandolo directamente al proveedor si no estamos en edicion y lo soporta.
1443
        if (filter == null) {
1444
            return;
1445
        }
1446
        boolean pendingFinishEditing = false;
1447
        DisposableFeatureSetIterable features = null;
1448
        try {
1449
            switch (this.mode) {
1450
                case MODE_QUERY:
1451
                    pendingFinishEditing = true;
1452
                    this.edit();
1453
                    break;
1454
                case MODE_APPEND:
1455
                    throw new IllegalStateException("Delete not allowed in append mode.");
1456
                case MODE_FULLEDIT:
1457
                    break;
1458
                case MODE_PASS_THROUGH:
1459
//                    this.provider.passThroughDelete(filter);
1460
//                    return;
1461
                    break;
1462
                default:
1463
                    throw new IllegalStateException("Mode " + this.mode + " not supported.");
1464
            }
1465

    
1466
            FeatureSet fset = this.getFeatureSet(filter);
1467
            features = fset.iterable();
1468
            for (Feature f : features) {
1469
                fset.delete(f);
1470
            }
1471
        } catch (DataException ex) {
1472
            throw new DataRuntimeException(ex.getFormatString(), ex.getMessageKey(), ex.getCode()) {
1473
            };
1474
        } catch (Exception ex) {
1475
            throw new RuntimeException("Can't delete features (" + filter.getPhrase() + ").", ex);
1476
        } finally {
1477
            if (pendingFinishEditing) {
1478
                this.finishEditingQuietly();
1479
            }
1480
            DisposeUtils.disposeQuietly(features);
1481
        }
1482
    }
1483

    
1484
    synchronized public void doDelete(Feature feature) throws DataException {
1485
        if (feature == null) {
1486
            throw new IllegalArgumentException("feature argument can't be null.");
1487
        }
1488
        try {
1489
            checkInEditingMode();
1490
            checkIsOwnFeature(feature);
1491
            if (feature instanceof EditableFeature && !((EditableFeature)feature).isUpdatable()) {
1492
                //La feature no est? persistida en disco
1493
                throw new StoreDeleteEditableFeatureException(getName());
1494
            }
1495
            if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1496
                return;
1497
            }
1498

    
1499
            //Update the featureManager and the spatialManager
1500
            featureManager.delete(feature);
1501
            spatialManager.deleteFeature(feature);
1502

    
1503
            newVersionOfUpdate();
1504
            hasStrongChanges = true;
1505
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1506
        } catch (Exception e) {
1507
            throw new StoreDeleteFeatureException(e, this.getName());
1508
        }
1509
    }
1510

    
1511
    @Override
1512
    public synchronized void insert(FeatureSet set) throws DataException {
1513
        switch (mode) {
1514
            case MODE_QUERY:
1515
                throw new NeedEditingModeException(this.getName());
1516

    
1517
            case MODE_APPEND:
1518
            case MODE_FULLEDIT:
1519
            case MODE_PASS_THROUGH:
1520
            try {
1521
                set.accept((Object obj) -> {
1522
                    EditableFeature ef = createNewFeature((Feature) obj);
1523
                    insert(ef);
1524
                });
1525
            } catch (BaseException ex) {
1526
                throw new StoreInsertFeatureException(ex, this.getName());
1527
            }
1528
            break;
1529
        }
1530
    }
1531

    
1532
    private static EditableFeature lastChangedFeature = null;
1533

    
1534
    @Override
1535
    public synchronized void insert(EditableFeature feature)
1536
            throws DataException {
1537
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1538
        try {
1539
            switch (mode) {
1540
                case MODE_QUERY:
1541
                    throw new NeedEditingModeException(this.getName());
1542

    
1543
                case MODE_APPEND:
1544
                    checkIsOwnFeature(feature);
1545
                    if (feature.isUpdatable()) {
1546
                        throw new NoNewFeatureInsertException(this.getName());
1547
                    }
1548
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1549
                        return;
1550
                    }
1551
                    this.featureCount = null;
1552
                    feature.validate(CHECK_RULES_AT_EDITING);
1553
                    provider.append(((DefaultEditableFeature) feature).getData());
1554
                    hasStrongChanges = true;
1555
                    hasInserts = true;
1556
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1557
                    break;
1558

    
1559
                case MODE_FULLEDIT:
1560
                    if (feature.isUpdatable()) {
1561
                        throw new NoNewFeatureInsertException(this.getName());
1562
                    }
1563
                    feature.validate(CHECK_RULES_AT_EDITING);
1564
                    commands.insert(feature);
1565
                    break;
1566

    
1567
                case MODE_PASS_THROUGH:
1568
                    checkIsOwnFeature(feature);
1569
                    if (feature.isUpdatable()) {
1570
                        throw new NoNewFeatureInsertException(this.getName());
1571
                    }
1572
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1573
                        return;
1574
                    }
1575
                    feature.validate(CHECK_RULES_AT_EDITING);
1576
                    this.provider.passThroughInsert(((DefaultEditableFeature) feature).getData());
1577
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1578
                    break;
1579
            }
1580
        } catch (Exception e) {
1581
            throw new StoreInsertFeatureException(e, this.getName());
1582
        }
1583
    }
1584

    
1585
    synchronized public void doInsert(EditableFeature feature)
1586
            throws DataException {
1587
        checkIsOwnFeature(feature);
1588

    
1589
        waitForIndexes();
1590

    
1591
        if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1592
            return;
1593
        }
1594
        newVersionOfUpdate();
1595
        if ((lastChangedFeature == null)
1596
                || (lastChangedFeature.getSource() != feature.getSource())) {
1597
            lastChangedFeature = feature;
1598
            feature.validate(CHECK_RULES_AT_EDITING);
1599
            lastChangedFeature = null;
1600
        }
1601
        //Update the featureManager and the spatialManager
1602
        ((DefaultFeature) feature).setInserted(true);
1603
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1604

    
1605
        featureManager.add(feature);
1606
        spatialManager.insertFeature(newFeature);
1607

    
1608
        hasStrongChanges = true;
1609
        hasInserts = true;
1610
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1611
    }
1612

    
1613
    @Override
1614
    public void update(EditableFeature feature)
1615
            throws DataException {
1616
        switch (this.mode) {
1617
            case MODE_PASS_THROUGH:
1618
                checkIsOwnFeature(feature);
1619
                if (!feature.isUpdatable()) {
1620
                    throw new NoNewFeatureInsertException(this.getName());
1621
                }
1622
                if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1623
                    return;
1624
                }
1625
                feature.validate(CHECK_RULES_AT_EDITING);
1626
                this.provider.passThroughUpdate(((DefaultEditableFeature) feature).getData());
1627
                notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1628
                break;
1629
            case MODE_FULLEDIT:
1630
                if (feature.isUpdatable()) {
1631
                    commands.update(feature, feature.getSource());
1632
                    return;
1633
                }
1634
                // FIXME: Deberiamos lanzar aqui un error en lugar de hacer el insert.
1635
                //        O lanzar un mensaje al log?
1636
                insert(feature);
1637
                break;
1638
            default:
1639
                throw new NeedEditingModeException(this.getName());
1640
        }
1641
    }
1642

    
1643
    @Override
1644
    public void update(Object... parameters) throws DataException {
1645
        if (parameters.length == 1) {
1646
            Object param0 = parameters[0];
1647
            if (param0 instanceof EditableFeature) {
1648
                this.update((EditableFeature) param0);
1649
            } else if (param0 instanceof EditableFeatureType) {
1650
                this.update((EditableFeatureType) param0);
1651
            } else {
1652
                throw new IllegalArgumentException("Type of first parameter isn't supported");
1653
            }
1654
            return;
1655
        }
1656

    
1657
        Expression filter = null;
1658
        long end = parameters.length;
1659
        if (parameters.length % 2 == 1) { //IMPAR
1660
            Object param = parameters[parameters.length - 1];
1661
            if (param != null) {
1662
                if (param instanceof Expression) {
1663
                    filter = (Expression) param;
1664
                } else {
1665
                    filter = ExpressionUtils.createExpression(param.toString());
1666
                }
1667
            }
1668
        } else {
1669
            end = parameters.length - 1;
1670
        }
1671

    
1672
        switch (this.mode) {
1673
            case MODE_PASS_THROUGH:
1674
                this.provider.passThroughUpdate(
1675
                        //                    this.getName(), 
1676
                        parameters,
1677
                        filter);
1678
                break;
1679
            case MODE_FULLEDIT:
1680
                FeatureSet set = this.getFeatureSet(filter);
1681
                DisposableIterator it = set.fastIterator();
1682
                while (it.hasNext()) {
1683
                    Feature feature = (Feature) it.next();
1684
                    EditableFeature ef = feature.getEditable();
1685
                    for (int i = 0; i < end; i += 2) {
1686
                        String name = (String) parameters[i];
1687
                        Object value = parameters[i + 1];
1688
                        ef.set(name, value);
1689
                    }
1690
                    set.update(ef);
1691
                }
1692
                DisposeUtils.disposeQuietly(it);
1693
                DisposeUtils.disposeQuietly(set);
1694
                break;
1695
            default:
1696
                throw new NeedEditingModeException(this.getName());
1697
        }
1698
    }
1699

    
1700
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1701
            throws DataException {
1702
        try {
1703
            checkInEditingMode();
1704
            checkIsOwnFeature(feature);
1705
            if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1706
                return;
1707
            }
1708
            newVersionOfUpdate();
1709
            if ((lastChangedFeature == null)
1710
                    || (lastChangedFeature.getSource() != feature.getSource())) {
1711
                lastChangedFeature = feature;
1712
                feature.validate(CHECK_RULES_AT_EDITING);
1713
                lastChangedFeature = null;
1714
            }
1715

    
1716
            //Update the featureManager and the spatialManager
1717
            Feature newf = feature.getNotEditableCopy();
1718
            featureManager.update(feature, oldFeature);
1719
            spatialManager.updateFeature(newf, oldFeature);
1720

    
1721
            hasStrongChanges = true;
1722
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1723
        } catch (Exception e) {
1724
            throw new StoreUpdateFeatureException(e, this.getName());
1725
        }
1726
    }
1727

    
1728
    @Override
1729
    synchronized public void redo() throws RedoException {
1730
        Command redo = commands.getNextRedoCommand();
1731
        try {
1732
            checkInEditingMode();
1733
        } catch (NeedEditingModeException ex) {
1734
            throw new RedoException(redo, ex);
1735
        }
1736
        if (notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled()) {
1737
            return;
1738
        }
1739
        newVersionOfUpdate();
1740
        commands.redo();
1741
        hasStrongChanges = true;
1742
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1743
    }
1744

    
1745
    @Override
1746
    synchronized public void undo() throws UndoException {
1747
        Command undo = commands.getNextUndoCommand();
1748
        try {
1749
            checkInEditingMode();
1750
        } catch (NeedEditingModeException ex) {
1751
            throw new UndoException(undo, ex);
1752
        }
1753
        if (notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled()) {
1754
            return;
1755
        }
1756
        newVersionOfUpdate();
1757
        commands.undo();
1758
        hasStrongChanges = true;
1759
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1760
    }
1761

    
1762
    @Override
1763
    public List getRedoInfos() {
1764
        if (isEditing() && (commands != null)) {
1765
            return commands.getRedoInfos();
1766
        } else {
1767
            return null;
1768
        }
1769
    }
1770

    
1771
    @Override
1772
    public List getUndoInfos() {
1773
        if (isEditing() && (commands != null)) {
1774
            return commands.getUndoInfos();
1775
        } else {
1776
            return null;
1777
        }
1778
    }
1779

    
1780
    public synchronized FeatureCommandsStack getCommandsStack()
1781
            throws DataException {
1782
        checkInEditingMode();
1783
        return commands;
1784
    }
1785

    
1786
    @Override
1787
    public boolean cancelEditingQuietly() {
1788
        try {
1789
            this.cancelEditing();
1790
            return true;
1791
        } catch (Exception ex) {
1792
            LOGGER.debug("Can't cancel editing", ex);
1793
            return false;
1794
        }
1795
    }
1796

    
1797
    @Override
1798
    synchronized public void cancelEditing() throws DataException {
1799
        if (spatialManager != null) {
1800
            spatialManager.cancelModifies();
1801
        }
1802
        try {
1803
            switch (mode) {
1804
                case MODE_QUERY:
1805
                    throw new NeedEditingModeException(this.getName());
1806

    
1807
                case MODE_APPEND:
1808
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1809
                        return;
1810
                    }
1811
                    provider.abortAppend();
1812
                    exitEditingMode();
1813
                    ((FeatureSelection) this.getSelection()).deselectAll();
1814
                    updateIndexes();
1815
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1816
                    break;
1817

    
1818
                case MODE_FULLEDIT:
1819
                    boolean clearSelection = this.hasStrongChanges;
1820
                    if (this.selection instanceof FeatureReferenceSelection) {
1821
                        clearSelection = this.hasInserts;
1822
                    }
1823
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1824
                        return;
1825
                    }
1826
                    exitEditingMode();
1827
                    if (clearSelection) {
1828
                        ((FeatureSelection) this.getSelection()).deselectAll();
1829
                    }
1830
                    updateIndexes();
1831
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1832
                    break;
1833

    
1834
                case MODE_PASS_THROUGH:
1835
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1836
                        return;
1837
                    }
1838
                    exitEditingMode();
1839
                    ((FeatureSelection) this.getSelection()).deselectAll();
1840
                    updateIndexes();
1841
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1842
                    break;
1843
            }
1844
        } catch (Exception e) {
1845
            throw new StoreCancelEditingException(e, this.getName());
1846
        }
1847
    }
1848

    
1849
    @Override
1850
    public boolean finishEditingQuietly() {
1851
        try {
1852
            this.finishEditing();
1853
            return true;
1854
        } catch (Exception ex) {
1855
            LOGGER.debug("Can't finish editing", ex);
1856
            return false;
1857
        }
1858
    }
1859

    
1860
    @Override
1861
    synchronized public void finishEditing() throws DataException {
1862
        LOGGER.debug("finish editing of mode: {}", mode);
1863
        try {
1864

    
1865
            /*
1866
             * Selection needs to be cleared when editing stops
1867
             * to prevent conflicts with selection remaining from
1868
             * editing mode.
1869
             */
1870
//            ((FeatureSelection) this.getSelection()).deselectAll();
1871
            Map<String, List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1872
            switch (mode) {
1873
                case MODE_QUERY:
1874
                    throw new NeedEditingModeException(this.getName());
1875

    
1876
                case MODE_APPEND:
1877
                    if (selection != null) {
1878
                        selection = null;
1879
                    }
1880
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, this.editingSessionCode).isCanceled()) {
1881
                        return;
1882
                    }
1883
                    saveDALFile();
1884
                    provider.endAppend();
1885
                    exitEditingMode();
1886
                    this.updateComputedFields(computedFields);
1887
                    loadDALFile();
1888
                    updateIndexes();
1889
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING, this.editingSessionCode);
1890
                    break;
1891

    
1892
                case MODE_FULLEDIT:
1893
                    if (featureManager.hasChanges() || featureTypeManager.hasChanges()) {
1894
                        if (hasStrongChanges && !this.allowWrite()) {
1895
                            throw new WriteNotAllowedException(getName());
1896
                        }
1897
                        if (notifyChange(FeatureStoreNotification.PREPARING_FINISHEDITING,
1898
                                this.editingSessionCode).isCanceled()) {
1899
                            return;
1900
                        }
1901
                        if (hasStrongChanges) {
1902
                            validateFeaturesAtFinishEditing();
1903
                        }
1904
                        if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING,
1905
                                this.editingSessionCode,
1906
                                featureManager.getDeleted(),
1907
                                featureManager.getInsertedFeatures(),
1908
                                featureManager.getUpdatedFeatures(),
1909
                                featureTypeManager.getFeatureTypesChanged().iterator(),
1910
                                featureManager.isSelectionCompromised()).isCanceled()) {
1911
                            return;
1912
                        }
1913
                        saveDALFile();
1914
                        if (featureManager.isSelectionCompromised() && selection != null) {
1915
                            selection = null;
1916
                        }
1917
                        if (hasStrongChanges) {
1918
                            /*
1919
                         * This will throw a PerformEditingExceptionif the provider
1920
                         * does not accept the changes (for example, an invalid field name)
1921
                             */
1922
                            provider.performChanges(featureManager.getDeleted(),
1923
                                    featureManager.getInserted(),
1924
                                    featureManager.getUpdated(),
1925
                                    removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1926

    
1927
                        }
1928
                        this.updateComputedFields(computedFields);
1929
                        exitEditingMode();
1930
                        loadDALFile();
1931
                        updateIndexes();
1932
                        notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING, this.editingSessionCode);
1933
                    } else {
1934
                        exitEditingMode();
1935
                    }
1936
                    break;
1937
                case MODE_PASS_THROUGH:
1938
                    if (selection != null) {
1939
                        selection = null;
1940
                    }
1941
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, this.editingSessionCode).isCanceled()) {
1942
                        return;
1943
                    }
1944
                    exitEditingMode();
1945
                    updateIndexes();
1946
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING, this.editingSessionCode);
1947
                    break;
1948
            }
1949
        } catch (ValidateFeaturesException | WriteNotAllowedException ex) {
1950
            // Don't notify failed.
1951
            throw ex;
1952
        } catch (PerformEditingException pee) {
1953
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING, this.editingSessionCode);
1954
            throw new WriteException(provider.getSourceId().toString(), pee);
1955
        } catch (Exception e) {
1956
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING, this.editingSessionCode);
1957
            throw new FinishEditingException(e);
1958
        }
1959
    }
1960

    
1961
    @Override
1962
    public String getEditingSession() {
1963
        return this.editingSessionCode;
1964
    }
1965

    
1966
    private Map<String, List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
1967
        Map<String, List<FeatureAttributeDescriptor>> r = new HashMap<>();
1968

    
1969
        List<FeatureType> theTypes = new ArrayList<>();
1970
        theTypes.addAll(this.getFeatureTypes());
1971
        theTypes.add(this.getDefaultFeatureType());
1972
        for (int n = 0; n < theTypes.size(); n++) {
1973
            FeatureType type = theTypes.get(n);
1974
            for (FeatureAttributeDescriptor attrdesc : type) {
1975
                FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
1976
                if (emulator != null) {
1977
                    List<FeatureAttributeDescriptor> l = r.get(type.getId());
1978
                    if (l == null) {
1979
                        l = new ArrayList<>();
1980
                        r.put(type.getId(), l);
1981
                    }
1982
                    l.add(attrdesc);
1983
                }
1984
            }
1985
        }
1986
        return r;
1987
    }
1988

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

    
1991
        List<FeatureType> theTypes = new ArrayList<>();
1992
        theTypes.addAll(this.getFeatureTypes());
1993
        theTypes.add(this.getDefaultFeatureType());
1994
        for (int n = 0; n < theTypes.size(); n++) {
1995
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1996
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1997
            if (x != null && !x.isEmpty()) {
1998
                for (FeatureAttributeDescriptor attrdesc : x) {
1999
                    if (type.get(attrdesc.getName()) == null) {
2000
                        type.add(attrdesc);
2001
                    }
2002
                }
2003
            }
2004
        }
2005

    
2006
    }
2007

    
2008
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
2009
        // FIXME: Falta por implementar
2010
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
2011
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
2012
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
2013
//                if (attributeDescriptor.isComputed()) {
2014
//                    target.remove(attributeDescriptor.getName());
2015
//                }
2016
//            }
2017
//        }
2018
        return ftypes;
2019
    }
2020

    
2021
    private void saveDALFile() {
2022
        if( this.ignoreDALResource ) {
2023
            return;
2024
        }
2025
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2026
        try {
2027
            ResourcesStorage theResourcesStorage = this.getResourcesStorage();
2028
            if (theResourcesStorage == null || theResourcesStorage.isReadOnly()) {
2029
                return;
2030
            }
2031
            resource = theResourcesStorage.getResource("dal");
2032
            if (resource == null || resource.isReadOnly()) {
2033
                return;
2034
            }
2035
            DALFile dalFile = DALFile.getDALFile();
2036
            dalFile.setStore(this);
2037
            if (!dalFile.isEmpty()) {
2038
                dalFile.write(resource);
2039
            }
2040
        } catch (Throwable ex) {
2041
            LOGGER.warn("Can't save DAL resource", ex);
2042
        } finally {
2043
            IOUtils.closeQuietly(resource);
2044
        }
2045
    }
2046

    
2047
    private void loadDALFile() {
2048
        if( this.ignoreDALResource ) {
2049
            return;
2050
        }
2051
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2052
        ResourcesStorage theResourcesStorage = null;
2053
        try {
2054
            theResourcesStorage = this.getResourcesStorage();
2055
            if (theResourcesStorage == null) {
2056
                return;
2057
            }
2058
            resource = theResourcesStorage.getResource("dal");
2059
            if (resource == null || !resource.exists()) {
2060
                return;
2061
            }
2062
            DALFile dalFile = DALFile.getDALFile(resource);
2063
            if (!dalFile.isEmpty()) {
2064
                dalFile.updateStore(this);
2065
            }
2066
        } catch (Throwable ex) {
2067
            if (resource == null || theResourcesStorage == null) {
2068
                if (theResourcesStorage == null) {
2069
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=null)", ex);
2070
                } else {
2071
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2072
                }
2073
            } else {
2074
                LOGGER.warn("Can't load DAL resource (resname=" + resource.getName() + ", resurl=" + Objects.toString(resource.getURL()) + ", storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2075
            }
2076
        } finally {
2077
            IOUtils.closeQuietly(resource);
2078
        }
2079
    }
2080

    
2081
    /**
2082
     * Save changes in the provider without leaving the edit mode. Do not call
2083
     * observers to communicate a change of ediding mode. The operation's
2084
     * history is eliminated to prevent inconsistencies in the data.
2085
     *
2086
     * @throws DataException
2087
     */
2088
    @Override
2089
    synchronized public void commitChanges() throws DataException {
2090
        LOGGER.debug("commitChanges of mode: {}", mode);
2091
        if (!canCommitChanges()) {
2092
            throw new WriteNotAllowedException(getName());
2093
        }
2094
        try {
2095
            switch (mode) {
2096
                case MODE_QUERY:
2097
                    throw new NeedEditingModeException(this.getName());
2098

    
2099
                case MODE_APPEND:
2100
                    this.provider.endAppend();
2101
                    exitEditingMode();
2102
                    invalidateIndexes();
2103
                    this.provider.beginAppend();
2104
                    hasInserts = false;
2105
                    break;
2106

    
2107
                case MODE_FULLEDIT:
2108
                    if (hasStrongChanges && !this.allowWrite()) {
2109
                        throw new WriteNotAllowedException(getName());
2110
                    }
2111
                    // FIXME: OOhh!!!! no se disparan eventos, VCSGis no se entera de estos cambios.
2112
                    if (hasStrongChanges) {
2113
                        validateFeaturesAtFinishEditing();
2114
                        provider.performChanges(featureManager.getDeleted(),
2115
                                featureManager.getInserted(),
2116
                                featureManager.getUpdated(),
2117
                                removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2118
                    }
2119
                    invalidateIndexes();
2120
                    featureManager = new FeatureManager(this);
2121
                    featureTypeManager = new FeatureTypeManager(this);
2122
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
2123

    
2124
                    commands
2125
                            = new DefaultFeatureCommandsStack(this, featureManager,
2126
                                    spatialManager, featureTypeManager);
2127
                    featureCount = null;
2128
                    hasStrongChanges = false;
2129
                    hasInserts = false;
2130
                    break;
2131
            }
2132
        } catch (Exception e) {
2133
            throw new FinishEditingException(e);
2134
        }
2135
    }
2136

    
2137
    @Override
2138
    synchronized public boolean canCommitChanges() throws DataException {
2139
        if (!this.allowWrite()) {
2140
            return false;
2141
        }
2142
        switch (mode) {
2143
            default:
2144
            case MODE_QUERY:
2145
                return false;
2146

    
2147
            case MODE_APPEND:
2148
                return true;
2149

    
2150
            case MODE_FULLEDIT:
2151
                List types = this.getFeatureTypes();
2152
                for (int i = 0; i < types.size(); i++) {
2153
                    Object type = types.get(i);
2154
                    if (type instanceof DefaultEditableFeatureType) {
2155
                        if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
2156
                            return false;
2157
                        }
2158
                    }
2159
                }
2160
                return true;
2161
        }
2162
    }
2163

    
2164
    @Override
2165
    public void beginEditingGroup(String description)
2166
            throws NeedEditingModeException {
2167
        checkInEditingMode();
2168
        commands.startComplex(description);
2169
    }
2170

    
2171
    @Override
2172
    public void endEditingGroup() throws NeedEditingModeException {
2173
        checkInEditingMode();
2174
        commands.endComplex();
2175
    }
2176

    
2177
    @Override
2178
    public boolean isAppendModeSupported() {
2179
        return this.provider.supportsAppendMode();
2180
    }
2181

    
2182
    @Override
2183
    public void export(DataServerExplorer explorer, String provider,
2184
            NewFeatureStoreParameters params, String name) throws DataException {
2185

    
2186
        if (this.getFeatureTypes().size() != 1) {
2187
            throw new NotYetImplemented(
2188
                    "export whith more than one type not yet implemented");
2189
        }
2190
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2191
        FeatureStore target = null;
2192
        FeatureSet features = null;
2193
        DisposableIterator iterator = null;
2194
        try {
2195
            FeatureType type = this.getDefaultFeatureType();
2196
            if ((params.getDefaultFeatureType() == null)
2197
                    || (params.getDefaultFeatureType().size() == 0)) {
2198
                params.setDefaultFeatureType(type.getEditable());
2199

    
2200
            }
2201
            explorer.add(provider, params, true);
2202
            DataManager manager = DALLocator.getDataManager();
2203

    
2204
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2205
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2206

    
2207
            target = (FeatureStore) manager.openStore(provider, openParams);
2208
            FeatureType targetType = target.getDefaultFeatureType();
2209

    
2210
            target.edit(MODE_APPEND);
2211
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2212
            if (featureSelection.getSize() > 0) {
2213
                features = this.getFeatureSelection();
2214
            } else {
2215
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2216
                    FeatureQuery query = createFeatureQuery();
2217
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2218
                        query.getOrder().add(pkattr.getName(), true);
2219
                    }
2220
                    features = this.getFeatureSet(query);
2221
                } else {
2222
                    features = this.getFeatureSet();
2223
                }
2224
            }
2225
            iterator = features.fastIterator();
2226
            while (iterator.hasNext()) {
2227
                DefaultFeature feature = (DefaultFeature) iterator.next();
2228
                target.insert(target.createNewFeature(targetType, feature));
2229
            }
2230
            target.finishEditing();
2231
            target.dispose();
2232
        } catch (Exception e) {
2233
            throw new DataExportException(e, params.toString());
2234
        } finally {
2235
            dispose(iterator);
2236
            dispose(features);
2237
            dispose(target);
2238
        }
2239
    }
2240

    
2241
    @Override
2242
    public void copyTo(final FeatureStore target) {
2243
        boolean finishEditingAtEnd = false;
2244
        try {
2245
            if (!target.isEditing() && !target.isAppending()) {
2246
                finishEditingAtEnd = true;
2247
                target.edit(MODE_APPEND);
2248
            }
2249
            this.accept((Object obj) -> {
2250
                Feature f_src = (Feature) obj;
2251
                EditableFeature f_dst = target.createNewFeature(f_src);
2252
                target.insert(f_dst);
2253
            });
2254
            if (finishEditingAtEnd) {
2255
                target.finishEditing();
2256
            }
2257

    
2258
        } catch (Exception ex) {
2259
            try {
2260
                if (finishEditingAtEnd) {
2261
                    target.cancelEditing();
2262
                }
2263
            } catch (Exception ex1) {
2264
            }
2265
            throw new RuntimeException("Can't copy store.", ex);
2266
        }
2267

    
2268
    }
2269

    
2270
    //
2271
    // ====================================================================
2272
    // Obtencion de datos
2273
    // getDataCollection, getFeatureCollection
2274
    //
2275
    @Override
2276
    public DataSet getDataSet() throws DataException {
2277
        checkNotInAppendMode();
2278
        FeatureQuery query
2279
                = new DefaultFeatureQuery(this.getDefaultFeatureType());
2280
        return new DefaultFeatureSet(this, query);
2281
    }
2282

    
2283
    @Override
2284
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2285
        checkNotInAppendMode();
2286
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2287
    }
2288

    
2289
    @Override
2290
    public void getDataSet(Observer observer) throws DataException {
2291
        checkNotInAppendMode();
2292
        this.getFeatureSet(null, observer);
2293
    }
2294

    
2295
    @Override
2296
    public void getDataSet(DataQuery dataQuery, Observer observer)
2297
            throws DataException {
2298
        checkNotInAppendMode();
2299
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2300
    }
2301

    
2302
    @Override
2303
    public FeatureSet getFeatureSet() throws DataException {
2304
        return this.getFeatureSet((FeatureQuery) null);
2305
    }
2306

    
2307
    @Override
2308
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2309
            throws DataException {
2310
        checkNotInAppendMode();
2311
        if (featureQuery == null) {
2312
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2313
        }
2314
        return new DefaultFeatureSet(this, featureQuery);
2315
    }
2316

    
2317
    @Override
2318
    public FeatureSet getFeatureSet(String filter) throws DataException {
2319
        return this.getFeatureSet(filter, null, true);
2320
    }
2321

    
2322
    @Override
2323
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2324
        return this.getFeatureSet(filter, sortBy, true);
2325
    }
2326

    
2327
    @Override
2328
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2329
        return this.getFeatureSet(filter, null, true);
2330
    }
2331

    
2332
    @Override
2333
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2334
        return this.getFeatureSet(filter, sortBy, true);
2335
    }
2336

    
2337
    @Override
2338
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2339
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2340
        return this.getFeatureSet(query);
2341
    }
2342

    
2343
    @Override
2344
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2345
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2346
        return this.getFeatureSet(query);
2347
    }
2348

    
2349
    @Override
2350
    public List<Feature> getFeatures(String filter) {
2351
        return this.getFeatures(filter, null, true);
2352
    }
2353

    
2354
    @Override
2355
    public List<Feature> getFeatures(String filter, String sortBy) {
2356
        return this.getFeatures(filter, sortBy, true);
2357
    }
2358

    
2359
    @Override
2360
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc) {
2361
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2362
        return this.getFeatures(query, 0);
2363
    }
2364

    
2365
    @Override
2366
    public List<Feature> getFeatures(Expression filter) {
2367
        return this.getFeatures(filter, null, true);
2368
    }
2369

    
2370
    @Override
2371
    public List<Feature> getFeatures(Expression filter, String sortBy) {
2372
        return this.getFeatures(filter, sortBy, true);
2373
    }
2374

    
2375
    @Override
2376
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc) {
2377
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2378
        return this.getFeatures(query, 0);
2379
    }
2380

    
2381
    @Override
2382
    public List<Feature> getFeatures(FeatureQuery query) {
2383
        return this.getFeatures(query, 0);
2384
    }
2385

    
2386
    @Override
2387
    public List<Feature> getFeatures(FeatureQuery query, int pageSize) {
2388
        try {
2389
            if (pageSize <= 0) {
2390
                pageSize = 100;
2391
            }
2392
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2393
            return pager.asList();
2394
        } catch (BaseException ex) {
2395
            throw new RuntimeException("Can't create the list of features.", ex);
2396
        }
2397
    }
2398
        
2399
    @Override
2400
    public List<Feature> getFeatures() {
2401
        return this.getFeatures(null, 0);
2402
    }
2403

    
2404
    @Override
2405
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2406
        return this.getFeatures64(null, 0);
2407
    }
2408

    
2409
    @Override
2410
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2411
        return this.getFeatures64(filter, null, true);
2412
    }
2413

    
2414
    @Override
2415
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc) {
2416
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2417
        return this.getFeatures64(query, 0);
2418
    }
2419

    
2420
    @Override
2421
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize) {
2422
        try {
2423
            if (pageSize <= 0) {
2424
                pageSize = 100;
2425
            }
2426
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2427
            return pager;
2428
        } catch (BaseException ex) {
2429
            throw new RuntimeException("Can't create the list of features.", ex);
2430
        }
2431
    }
2432

    
2433
    @Override
2434
    public Feature first() throws DataException {
2435
        return this.findFirst((FeatureQuery) null);
2436
    }
2437

    
2438
    @Override
2439
    public Feature findFirst(String filter) throws DataException {
2440
        return this.findFirst(filter, (String) null, true);
2441
    }
2442

    
2443
    @Override
2444
    public Feature findFirst(String filter, String sortBy) throws DataException {
2445
        return this.findFirst(filter, sortBy, true);
2446
    }
2447

    
2448
    @Override
2449
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2450
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2451
        return findFirst(query);
2452
    }
2453

    
2454
    @Override
2455
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2456
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2457
        return findFirst(query);
2458
    }
2459

    
2460
    @Override
2461
    public Feature findFirst(Expression filter) throws DataException {
2462
        return this.findFirst(filter, (String) null, true);
2463
    }
2464

    
2465
    @Override
2466
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2467
        return this.findFirst(filter, sortBy, true);
2468
    }
2469

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

    
2476
    @Override
2477
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2478
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2479
        return findFirst(query);
2480
    }
2481

    
2482
    @Override
2483
    public Feature findFirst(FeatureQuery query) throws DataException {
2484
        if (query == null) {
2485
            query = this.createFeatureQuery();
2486
        } else {
2487
            query = query.getCopy();
2488
        }
2489
        query.setLimit(1);
2490
        final MutableObject<Feature> feature = new MutableObject<>();
2491
        try {
2492
            this.accept((Object obj) -> {
2493
                feature.setValue((Feature) obj);
2494
                throw new VisitCanceledException();
2495
            }, query);
2496
        } catch (VisitCanceledException ex) {
2497

    
2498
        } catch (DataException ex) {
2499
            throw ex;
2500
        } catch (Exception ex) {
2501
            throw new RuntimeException("", ex);
2502
        }
2503
        return feature.getValue();
2504
    }
2505

    
2506
    @Override
2507
    public void accept(Visitor visitor) throws BaseException {
2508
        this.accept(visitor, null);
2509
    }
2510

    
2511
    @Override
2512
    public void accept(Visitor visitor, DataQuery dataQuery)
2513
            throws BaseException {
2514
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2515
        try {
2516
            set.accept(visitor);
2517
        } finally {
2518
            set.dispose();
2519
        }
2520
    }
2521

    
2522
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2523
            throws DataException {
2524
        DefaultFeatureType fType
2525
                = (DefaultFeatureType) this.getFeatureType(featureQuery
2526
                        .getFeatureTypeId());
2527
        if (featureQuery.hasAttributeNames()
2528
                || featureQuery.hasConstantsAttributeNames()
2529
                || fType.hasRequiredFields()) {
2530
            if (featureQuery.hasGroupByColumns()) {
2531
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false);
2532
            } else {
2533
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2534
            }
2535
        }
2536
        return fType;
2537
    }
2538

    
2539
    @Override
2540
    public void getFeatureSet(Observer observer) throws DataException {
2541
        checkNotInAppendMode();
2542
        this.getFeatureSet(null, observer);
2543
    }
2544

    
2545
    @Override
2546
    public void getFeatureSet(FeatureQuery query, Observer observer)
2547
            throws DataException {
2548
        class LoadInBackGround implements Runnable {
2549

    
2550
            private final FeatureStore store;
2551
            private final FeatureQuery query;
2552
            private final Observer observer;
2553

    
2554
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2555
                    Observer observer) {
2556
                this.store = store;
2557
                this.query = query;
2558
                this.observer = observer;
2559
            }
2560

    
2561
            void notify(FeatureStoreNotification theNotification) {
2562
                observer.update(store, theNotification);
2563
            }
2564

    
2565
            @Override
2566
            public void run() {
2567
                FeatureSet set = null;
2568
                try {
2569
                    set = store.getFeatureSet(query);
2570
                    notify(new DefaultFeatureStoreNotification(store,
2571
                            FeatureStoreNotification.LOAD_FINISHED, set));
2572
                } catch (Exception e) {
2573
                    notify(new DefaultFeatureStoreNotification(store,
2574
                            FeatureStoreNotification.LOAD_FINISHED, e));
2575
                } finally {
2576
                    dispose(set);
2577
                }
2578
            }
2579
        }
2580

    
2581
        checkNotInAppendMode();
2582
        if (query == null) {
2583
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2584
        }
2585
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2586
        Thread thread = new Thread(task, "Load Feature Set in background");
2587
        thread.start();
2588
    }
2589

    
2590
    @Override
2591
    public Feature getFeatureByReference(FeatureReference reference)
2592
            throws DataException {
2593
        checkNotInAppendMode();
2594
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2595
        FeatureType featureType;
2596
        if (ref.getFeatureTypeId() == null) {
2597
            featureType = this.getDefaultFeatureType();
2598
        } else {
2599
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2600
        }
2601
        return this.getFeatureByReference(reference, featureType);
2602
    }
2603

    
2604
    @Override
2605
    public Feature getFeatureByReference(FeatureReference reference,
2606
            FeatureType featureType) throws DataException {
2607
        checkNotInAppendMode();
2608
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2609
        if (this.mode == MODE_FULLEDIT) {
2610
            Feature f = featureManager.get(reference, this, featureType);
2611
            if (f != null) {
2612
                return f;
2613
            }
2614
        }
2615

    
2616
        FeatureType sourceFeatureType = featureType;
2617
        if (!this.transforms.isEmpty()) {
2618
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2619
        }
2620
        // TODO comprobar que el id es de este store
2621

    
2622
        DefaultFeature feature
2623
                = new DefaultFeature(this,
2624
                        this.provider.getFeatureProviderByReference(
2625
                                (FeatureReferenceProviderServices) reference, sourceFeatureType));
2626

    
2627
        if (!this.transforms.isEmpty()) {
2628
            return this.transforms.applyTransform(feature, featureType);
2629
        }
2630
        return feature;
2631
    }
2632

    
2633
    //
2634
    // ====================================================================
2635
    // Gestion de features
2636
    //
2637
    private FeatureType fixFeatureType(DefaultFeatureType type)
2638
            throws DataException {
2639
        FeatureType original = this.getDefaultFeatureType();
2640

    
2641
        if ((type == null) || type.equals(original)) {
2642
            return original;
2643
        } else {
2644
            if (!type.isSubtypeOf(original)) {
2645
                Iterator iter = this.getFeatureTypes().iterator();
2646
                FeatureType tmpType;
2647
                boolean found = false;
2648
                while (iter.hasNext()) {
2649
                    tmpType = (FeatureType) iter.next();
2650
                    if (type.equals(tmpType)) {
2651
                        return type;
2652

    
2653
                    } else if (type.isSubtypeOf(tmpType)) {
2654
                        found = true;
2655
                        original = tmpType;
2656
                        break;
2657
                    }
2658

    
2659
                }
2660
                if (!found) {
2661
                    throw new IllegalFeatureTypeException(getName());
2662
                }
2663
            }
2664
        }
2665

    
2666
        // Checks that type has all fields of pk
2667
        // else add the missing attributes at the end.
2668
        if (!original.hasOID()) {
2669
            // Gets original pk attributes
2670
            DefaultEditableFeatureType edOriginal
2671
                    = (DefaultEditableFeatureType) original.getEditable();
2672
            FeatureAttributeDescriptor orgAttr;
2673
            Iterator edOriginalIter = edOriginal.iterator();
2674
            while (edOriginalIter.hasNext()) {
2675
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2676
                if (!orgAttr.isPrimaryKey()) {
2677
                    edOriginalIter.remove();
2678
                }
2679
            }
2680

    
2681
            // Checks if all pk attributes are in type
2682
            Iterator typeIterator;
2683
            edOriginalIter = edOriginal.iterator();
2684
            FeatureAttributeDescriptor attr;
2685
            while (edOriginalIter.hasNext()) {
2686
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2687
                typeIterator = type.iterator();
2688
                while (typeIterator.hasNext()) {
2689
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2690
                    if (attr.getName().equals(orgAttr.getName())) {
2691
                        edOriginalIter.remove();
2692
                        break;
2693
                    }
2694
                }
2695
            }
2696

    
2697
            // add missing pk attributes if any
2698
            if (edOriginal.size() > 0) {
2699
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2700
                DefaultEditableFeatureType edType
2701
                        = (DefaultEditableFeatureType) original.getEditable();
2702
                edType.clear();
2703
                edType.addAll(type);
2704
                edType.addAll(edOriginal);
2705
                if (!isEditable) {
2706
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2707
                }
2708
            }
2709

    
2710
        }
2711

    
2712
        return type;
2713
    }
2714

    
2715
    private void validateFeaturesAtFinishEditing() throws ValidateFeaturesException {
2716
        try {
2717
            checkInEditingMode();
2718
            FeatureType type = this.getDefaultFeatureTypeQuietly();
2719
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
2720

    
2721
            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS : 0;
2722
            checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
2723
            if (checks == 0) {
2724
                return;
2725
            }
2726

    
2727
            Iterator<EditableFeature> features = new ChainedIterator<>(
2728
                    featureManager.getInsertedFeatures(),
2729
                    featureManager.getUpdatedFeatures()
2730
            );
2731
            while (features.hasNext()) {
2732
                EditableFeature feature = features.next();
2733
                rules.validate(feature, checks);
2734
            }
2735
        } catch (Exception ex) {
2736
            throw new ValidateFeaturesException(this.getName(), ex);
2737
        }
2738
    }
2739

    
2740
    @Override
2741
    public FeatureType getDefaultFeatureType() throws DataException {
2742
        try {
2743

    
2744
            if (isEditing()) {
2745
                FeatureType auxFeatureType
2746
                        = featureTypeManager.getType(defaultFeatureType.getId());
2747
                if (auxFeatureType != null) {
2748
                    return avoidEditable(auxFeatureType);
2749
                }
2750
            }
2751
            FeatureType type = this.transforms.getDefaultFeatureType();
2752
            if (type != null) {
2753
                return avoidEditable(type);
2754
            }
2755

    
2756
            return avoidEditable(defaultFeatureType);
2757

    
2758
        } catch (Exception e) {
2759
            throw new GetFeatureTypeException(e, getName());
2760
        }
2761
    }
2762

    
2763
    @Override
2764
    public FeatureType getDefaultFeatureTypeQuietly() {
2765
        try {
2766
            return this.getDefaultFeatureType();
2767
        } catch (Exception ex) {
2768
            return null;
2769
        }
2770
    }
2771

    
2772
    private FeatureType avoidEditable(FeatureType ft) {
2773
        if (ft instanceof EditableFeatureType) {
2774
            return ((EditableFeatureType) ft).getNotEditableCopy();
2775
        } else {
2776
            return ft;
2777
        }
2778
    }
2779

    
2780
    @Override
2781
    public FeatureType getFeatureType(String featureTypeId)
2782
            throws DataException {
2783
        if (featureTypeId == null) {
2784
            return this.getDefaultFeatureType();
2785
        }
2786
        try {
2787
            if (isEditing()) {
2788
                FeatureType auxFeatureType
2789
                        = featureTypeManager.getType(featureTypeId);
2790
                if (auxFeatureType != null) {
2791
                    return auxFeatureType;
2792
                }
2793
            }
2794
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2795
            if (type != null) {
2796
                return type;
2797
            }
2798
            Iterator iter = this.featureTypes.iterator();
2799
            while (iter.hasNext()) {
2800
                type = (FeatureType) iter.next();
2801
                if (type.getId().equals(featureTypeId)) {
2802
                    return type;
2803
                }
2804
            }
2805
            return null;
2806
        } catch (Exception e) {
2807
            throw new GetFeatureTypeException(e, getName());
2808
        }
2809
    }
2810

    
2811
    public FeatureType getProviderDefaultFeatureType() {
2812
        return defaultFeatureType;
2813
    }
2814

    
2815
    @Override
2816
    public List getFeatureTypes() throws DataException {
2817
        try {
2818
            List types;
2819
            if (isEditing()) {
2820
                types = new ArrayList();
2821
                for (FeatureType type : featureTypes) {
2822
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2823
                    if (typeaux != null) {
2824
                        types.add(typeaux);
2825
                    } else {
2826
                        types.add(type);
2827
                    }
2828
                }
2829
                Iterator it = featureTypeManager.newsIterator();
2830
                while (it.hasNext()) {
2831
                    FeatureType type = (FeatureType) it.next();
2832
                    types.add(type);
2833
                }
2834
            } else {
2835
                types = this.transforms.getFeatureTypes();
2836
                if (types == null) {
2837
                    types = featureTypes;
2838
                }
2839
            }
2840
            return Collections.unmodifiableList(types);
2841
        } catch (Exception e) {
2842
            throw new GetFeatureTypeException(e, getName());
2843
        }
2844
    }
2845

    
2846
    public List getProviderFeatureTypes() throws DataException {
2847
        return Collections.unmodifiableList(this.featureTypes);
2848
    }
2849

    
2850
    @Override
2851
    public Feature createFeature(FeatureProvider data) throws DataException {
2852
        DefaultFeature feature = new DefaultFeature(this, data);
2853
        return feature;
2854
    }
2855

    
2856
    public Feature createFeature(FeatureProvider data, FeatureType type)
2857
            throws DataException {
2858
        // FIXME: falta por implementar
2859
        // Comprobar si es un subtipo del feature de data
2860
        // y construir un feature usando el subtipo.
2861
        // Probablemente requiera generar una copia del data.
2862
        throw new NotYetImplemented();
2863
    }
2864

    
2865
    @Override
2866
    public EditableFeature createNewFeature(FeatureType type,
2867
            Feature defaultValues) throws DataException {
2868
        try {
2869
            FeatureProvider data = createNewFeatureProvider(type);
2870
            DefaultEditableFeature feature
2871
                    = new DefaultEditableFeature(this, data);
2872
            feature.initializeValues(defaultValues);
2873
            data.setNew(true);
2874

    
2875
            return feature;
2876
        } catch (Exception e) {
2877
            throw new CreateFeatureException(e, getName());
2878
        }
2879
    }
2880

    
2881
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2882
            throws DataException {
2883
        type = this.fixFeatureType((DefaultFeatureType) type);
2884
        FeatureProvider data = this.provider.createFeatureProvider(type);
2885
        data.setNew(true);
2886
        if (type.hasOID() && (data.getOID() == null)) {
2887
            data.setOID(this.provider.createNewOID());
2888
        } else {
2889
            data.setOID(this.getTemporalOID());
2890
        }
2891
        return data;
2892

    
2893
    }
2894

    
2895
    @Override
2896
    public EditableFeature createNewFeature(FeatureType type,
2897
            boolean defaultValues) throws DataException {
2898
        try {
2899
            FeatureProvider data = createNewFeatureProvider(type);
2900
            DefaultEditableFeature feature
2901
                    = new DefaultEditableFeature(this, data);
2902
            if (defaultValues) {
2903
                feature.initializeValues();
2904
            }
2905
            return feature;
2906
        } catch (Exception e) {
2907
            throw new CreateFeatureException(e, getName());
2908
        }
2909
    }
2910

    
2911
    @Override
2912
    public EditableFeature createNewFeature(boolean defaultValues)
2913
            throws DataException {
2914
        return this.createNewFeature(this.getDefaultFeatureType(),
2915
                defaultValues);
2916
    }
2917

    
2918
    @Override
2919
    public EditableFeature createNewFeature() throws DataException {
2920
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2921
    }
2922

    
2923
    @Override
2924
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2925
        FeatureType ft = this.getDefaultFeatureType();
2926
        EditableFeature f = this.createNewFeature(ft, false);
2927
        f.copyFrom(defaultValues);
2928
        return f;
2929
    }
2930

    
2931
    @Override
2932
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2933
        FeatureType ft = this.getDefaultFeatureType();
2934
        EditableFeature f = this.createNewFeature(ft, false);
2935
        f.copyFrom(defaultValues);
2936
        return f;
2937
    }
2938

    
2939
    @Override
2940
    public EditableFeatureType createFeatureType() {
2941
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2942
        return ftype;
2943
    }
2944

    
2945
    @Override
2946
    public EditableFeatureType createFeatureType(String id) {
2947
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2948
        return ftype;
2949
    }
2950

    
2951
    //
2952
    // ====================================================================
2953
    // Index related methods
2954
    //
2955
    @Override
2956
    public FeatureIndexes getIndexes() {
2957
        return this.indexes;
2958
    }
2959

    
2960
    @Override
2961
    public FeatureIndex createIndex(FeatureType featureType,
2962
            String attributeName, String indexName) throws DataException {
2963
        return createIndex(null, featureType, attributeName, indexName);
2964
    }
2965

    
2966
    @Override
2967
    public FeatureIndex createIndex(String indexTypeName,
2968
            FeatureType featureType, String attributeName, String indexName)
2969
            throws DataException {
2970

    
2971
        return createIndex(indexTypeName, featureType, attributeName,
2972
                indexName, false, null);
2973
    }
2974

    
2975
    @Override
2976
    public FeatureIndex createIndex(FeatureType featureType,
2977
            String attributeName, String indexName, Observer observer)
2978
            throws DataException {
2979
        return createIndex(null, featureType, attributeName, indexName,
2980
                observer);
2981
    }
2982

    
2983
    @Override
2984
    public FeatureIndex createIndex(String indexTypeName,
2985
            FeatureType featureType, String attributeName, String indexName,
2986
            final Observer observer) throws DataException {
2987

    
2988
        return createIndex(indexTypeName, featureType, attributeName,
2989
                indexName, true, observer);
2990
    }
2991

    
2992
    private FeatureIndex createIndex(String indexTypeName,
2993
            FeatureType featureType, String attributeName, String indexName,
2994
            boolean background, final Observer observer) throws DataException {
2995

    
2996
        checkNotInAppendMode();
2997
        FeatureIndexProviderServices index;
2998
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2999
                featureType, indexName,
3000
                featureType.getAttributeDescriptor(attributeName));
3001

    
3002
        try {
3003
            index.fill(background, observer);
3004
        } catch (FeatureIndexException e) {
3005
            throw new InitializeException(index.getName(), e);
3006
        }
3007

    
3008
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
3009
        return index;
3010
    }
3011

    
3012
    //
3013
    // ====================================================================
3014
    // Transforms related methods
3015
    //
3016
    @Override
3017
    public FeatureStoreTransforms getTransforms() {
3018
        return this.transforms;
3019
    }
3020

    
3021
    @Override
3022
    public FeatureQuery createFeatureQuery() {
3023
        return new DefaultFeatureQuery(this.getName());
3024
    }
3025

    
3026
    @Override
3027
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
3028
        FeatureQuery query = null;
3029
        if (filter != null) {
3030
            query = this.createFeatureQuery();
3031
            query.setFilter(filter);
3032
        }
3033
        if (!StringUtils.isBlank(sortBy)) {
3034
            if (query == null) {
3035
                query = this.createFeatureQuery();
3036
            }
3037
            if (StringUtils.containsAny(sortBy, "(", ")")) {
3038
                throw new IllegalArgumentException("Incorrect sortBy expression");
3039
            }
3040
            String[] attrnames;
3041
            if (sortBy.contains(",")) {
3042
                attrnames = StringUtils.split(sortBy, ",");
3043
            } else {
3044
                attrnames = new String[]{sortBy};
3045
            }
3046
            for (String attrname : attrnames) {
3047
                attrname = attrname.trim();
3048
                if (attrname.startsWith("-")) {
3049
                    query.getOrder().add(attrname.substring(1).trim(), false);
3050
                } else if (attrname.endsWith("-")) {
3051
                    query.getOrder().add(attrname.substring(0, sortBy.length() - 1).trim(), false);
3052
                } else if (attrname.startsWith("+")) {
3053
                    query.getOrder().add(attrname.substring(1).trim(), true);
3054
                } else if (attrname.endsWith("-")) {
3055
                    query.getOrder().add(attrname.substring(0, sortBy.length() - 1).trim(), true);
3056
                } else {
3057
                    query.getOrder().add(attrname, asc);
3058
                }
3059
            }
3060
        }
3061
        if (query != null) {
3062
            query.retrievesAllAttributes();
3063
        }
3064
        return query;
3065
    }
3066

    
3067
    @Override
3068
    public FeatureQuery createFeatureQuery(String filter) {
3069
        return this.createFeatureQuery(
3070
                ExpressionUtils.createExpression(filter),
3071
                (String) null,
3072
                true
3073
        );
3074
    }
3075

    
3076
    @Override
3077
    public FeatureQuery createFeatureQuery(Expression filter) {
3078
        return this.createFeatureQuery(
3079
                filter,
3080
                (String) null,
3081
                true
3082
        );
3083
    }
3084

    
3085
    @Override
3086
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
3087
        if (StringUtils.isBlank(filter)) {
3088
            return this.createFeatureQuery(
3089
                    (Expression) null,
3090
                    sortBy,
3091
                    asc
3092
            );
3093
        } else {
3094
            return this.createFeatureQuery(
3095
                    ExpressionUtils.createExpression(filter),
3096
                    sortBy,
3097
                    asc
3098
            );
3099
        }
3100
    }
3101

    
3102
    @Override
3103
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
3104
        FeatureQuery query = null;
3105
        if (filter != null) {
3106
            query = this.createFeatureQuery();
3107
            query.setFilter(filter);
3108
        }
3109
        if (sortBy != null) {
3110
            if (query == null) {
3111
                query = this.createFeatureQuery();
3112
            }
3113
            query.getOrder().add(sortBy, asc);
3114
        }
3115

    
3116
        if (query != null) {
3117
            query.retrievesAllAttributes();
3118
        }
3119
        return query;
3120
    }
3121

    
3122
    @Override
3123
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3124
        if (StringUtils.isBlank(filter)) {
3125
            return this.createFeatureQuery(
3126
                    (Expression) null,
3127
                    sortBy,
3128
                    asc
3129
            );
3130
        } else {
3131
            return this.createFeatureQuery(
3132
                    ExpressionUtils.createExpression(filter),
3133
                    sortBy,
3134
                    asc
3135
            );
3136
        }
3137
    }
3138

    
3139
    @Override
3140
    public DataQuery createQuery() {
3141
        return createFeatureQuery();
3142
    }
3143

    
3144
    //
3145
    // ====================================================================
3146
    // UndoRedo related methods
3147
    //
3148
    @Override
3149
    public boolean canRedo() {
3150
        return commands.canRedo();
3151
    }
3152

    
3153
    @Override
3154
    public boolean canUndo() {
3155
        return commands.canUndo();
3156
    }
3157

    
3158
    @Override
3159
    public void redo(int num) throws RedoException {
3160
        for (int i = 0; i < num; i++) {
3161
            redo();
3162
        }
3163
    }
3164

    
3165
    @Override
3166
    public void undo(int num) throws UndoException {
3167
        for (int i = 0; i < num; i++) {
3168
            undo();
3169
        }
3170
    }
3171

    
3172
    //
3173
    // ====================================================================
3174
    // Metadata related methods
3175
    //
3176
    @Override
3177
    public Object getMetadataID() {
3178
        return this.provider.getSourceId();
3179
    }
3180

    
3181
    @Override
3182
    public void delegate(DynObject dynObject) {
3183
        this.metadata.delegate(dynObject);
3184
    }
3185

    
3186
    @Override
3187
    public DynClass getDynClass() {
3188
        return this.metadata.getDynClass();
3189
    }
3190

    
3191
    @Override
3192
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3193
        try {
3194
            if (this.transforms.hasDynValue(name)) {
3195
                return this.transforms.getDynValue(name);
3196
            }
3197
            if (this.metadata.hasDynValue(name)) {
3198
                return this.metadata.getDynValue(name);
3199
            }
3200
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3201
                return this.provider.getProviderName();
3202
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3203
                return this.provider.getSourceId();
3204
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3205
                try {
3206
                    return this.getDefaultFeatureType();
3207
                } catch (DataException e) {
3208
                    return null;
3209
                }
3210
            }
3211
            return this.metadata.getDynValue(name);
3212
        } catch (Exception ex) {
3213
            LOGGER.debug("Can't retrieve the value of '" + name + "' in store '" + this.getName() + "'.", ex);
3214
            return null;
3215
        }
3216
    }
3217

    
3218
    @Override
3219
    public boolean hasDynValue(String name) {
3220
        if (this.transforms.hasDynValue(name)) {
3221
            return true;
3222
        }
3223
        return this.metadata.hasDynValue(name);
3224
    }
3225

    
3226
    @Override
3227
    public boolean hasDynMethod(String name) {
3228
        return ((DynObject_v2) this.metadata).hasDynMethod(name);
3229
    }
3230

    
3231
    @Override
3232
    public void implement(DynClass dynClass) {
3233
        this.metadata.implement(dynClass);
3234
    }
3235

    
3236
    @Override
3237
    public Object invokeDynMethod(String name, Object[] args)
3238
            throws DynMethodException {
3239
        return this.metadata.invokeDynMethod(this, name, args);
3240
    }
3241

    
3242
    @Override
3243
    public Object invokeDynMethod(int code, Object[] args)
3244
            throws DynMethodException {
3245
        return this.metadata.invokeDynMethod(this, code, args);
3246
    }
3247

    
3248
    @Override
3249
    public void setDynValue(String name, Object value)
3250
            throws DynFieldNotFoundException {
3251
        if (this.transforms.hasDynValue(name)) {
3252
            this.transforms.setDynValue(name, value);
3253
            return;
3254
        }
3255
        this.metadata.setDynValue(name, value);
3256

    
3257
    }
3258

    
3259
    /*
3260
     * (non-Javadoc)
3261
     *
3262
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3263
     */
3264
    @Override
3265
    public Set getMetadataChildren() {
3266
        return this.metadataChildren;
3267
    }
3268

    
3269
    /*
3270
     * (non-Javadoc)
3271
     *
3272
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3273
     */
3274
    @Override
3275
    public String getMetadataName() {
3276
        return this.provider.getProviderName();
3277
    }
3278

    
3279
    public FeatureTypeManager getFeatureTypeManager() {
3280
        return this.featureTypeManager;
3281
    }
3282

    
3283
    @Override
3284
    public long getFeatureCount() throws DataException {
3285
        if (featureCount == null) {
3286
            featureCount = this.provider.getFeatureCount();
3287
        }
3288
        if (this.isEditing()) {
3289
            if (this.isAppending()) {
3290
                try {
3291
                    throw new IllegalStateException();
3292
                } catch (IllegalStateException e) {
3293
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND", e);
3294
                }
3295
                return -1;
3296
            } else {
3297
                return featureCount
3298
                        + this.featureManager.getDeltaSize();
3299
            }
3300
        }
3301
        return featureCount;
3302
    }
3303

    
3304
    private Long getTemporalOID() {
3305
        return this.temporalOid++;
3306
    }
3307

    
3308
    @Override
3309
    public FeatureType getProviderFeatureType(String featureTypeId) {
3310
        if (featureTypeId == null) {
3311
            return this.defaultFeatureType;
3312
        }
3313
        FeatureType type;
3314
        Iterator iter = this.featureTypes.iterator();
3315
        while (iter.hasNext()) {
3316
            type = (FeatureType) iter.next();
3317
            if (type.getId().equals(featureTypeId)) {
3318
                return type;
3319
            }
3320
        }
3321
        return null;
3322
    }
3323

    
3324
    @Override
3325
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3326
        return ((DefaultFeature) feature).getData();
3327
    }
3328

    
3329
    @Override
3330
    public DataStore getStore() {
3331
        return this;
3332
    }
3333

    
3334
    @Override
3335
    public FeatureStore getFeatureStore() {
3336
        return this;
3337
    }
3338

    
3339
    @Override
3340
    public void createCache(String name, DynObject parameters)
3341
            throws DataException {
3342
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3343
        if (cache == null) {
3344
            throw new CreateException("FeaureCacheProvider", null);
3345
        }
3346
        cache.apply(this, provider);
3347
        provider = cache;
3348

    
3349
        featureCount = null;
3350
    }
3351

    
3352
    @Override
3353
    public FeatureCache getCache() {
3354
        return cache;
3355
    }
3356

    
3357
    @Override
3358
    public void clear() {
3359
        if (metadata != null) {
3360
            metadata.clear();
3361
        }
3362
    }
3363

    
3364
    @Override
3365
    public String getName() {
3366
        if (this.provider != null) {
3367
            return this.provider.getName();
3368
        }
3369
        if (this.parameters instanceof HasAFile) {
3370
            return FilenameUtils.getName(((HasAFile) this.parameters).getFile().getName());
3371
        }
3372
        return "unknow";
3373
    }
3374

    
3375
    @Override
3376
    public String getFullName() {
3377
        try {
3378
            if (this.provider != null) {
3379
                return this.provider.getFullName();
3380
            }
3381
            if (this.parameters instanceof HasAFile) {
3382
                return (((HasAFile) this.parameters).getFile().getAbsolutePath());
3383
            }
3384
            return null;
3385
        } catch (Throwable th) {
3386
            return null;
3387
        }
3388
    }
3389

    
3390
    @Override
3391
    public String getProviderName() {
3392
        if (this.provider != null) {
3393
            return this.provider.getProviderName();
3394
        }
3395
        if (this.parameters != null) {
3396
            return this.parameters.getDataStoreName();
3397
        }
3398
        return null;
3399

    
3400
    }
3401

    
3402
    @Override
3403
    public boolean isKnownEnvelope() {
3404
        return this.provider.isKnownEnvelope();
3405
    }
3406

    
3407
    @Override
3408
    public boolean hasRetrievedFeaturesLimit() {
3409
        return this.provider.hasRetrievedFeaturesLimit();
3410
    }
3411

    
3412
    @Override
3413
    public int getRetrievedFeaturesLimit() {
3414
        return this.provider.getRetrievedFeaturesLimit();
3415
    }
3416

    
3417
    @Override
3418
    public Interval getInterval() {
3419
        if (this.timeSupport != null) {
3420
            return this.timeSupport.getInterval();
3421
        }
3422
        try {
3423
            FeatureType type = this.getDefaultFeatureType();
3424
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3425
            if (attr != null) {
3426
                Interval interval = attr.getInterval();
3427
                if (interval != null) {
3428
                    return interval;
3429
                }
3430
            }
3431
        } catch (DataException ex) {
3432
        }
3433
        return this.provider.getInterval();
3434
    }
3435

    
3436
    @Override
3437
    public Collection getTimes() {
3438
        if (this.timeSupport != null) {
3439
            return this.timeSupport.getTimes();
3440
        }
3441
        return this.provider.getTimes();
3442
    }
3443

    
3444
    @Override
3445
    public Collection getTimes(Interval interval) {
3446
        if (this.timeSupport != null) {
3447
            return this.timeSupport.getTimes(interval);
3448
        }
3449
        return this.provider.getTimes(interval);
3450
    }
3451

    
3452
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3453
        if (this.isEditing()) {
3454
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' while store is editing.");
3455
        }
3456
        if (!this.transforms.isEmpty()) {
3457
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' if has transforms.");
3458
        }
3459
        FeatureType ft = this.defaultFeatureType;
3460
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3461
        if (attr == null) {
3462
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "', this attribute don't exists.");
3463
        }
3464
        EditableFeatureType eft = ft.getEditable();
3465
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3466
        if (attr != null) {
3467
            if (!(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport)) {
3468
                throw new RuntimeException("Can't add time support, attribute '" + timeSupport.getAttributeName() + "'already exists.");
3469
            }
3470
            eft.remove(attr.getName());
3471
        }
3472
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3473
                timeSupport.getAttributeName(),
3474
                timeSupport.getDataType()
3475
        );
3476
        attrTime.setIsTime(true);
3477
        attrTime.setFeatureAttributeEmulator(timeSupport);
3478
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3479
        this.defaultFeatureType = eft.getNotEditableCopy();
3480

    
3481
        this.timeSupport = timeSupport;
3482
    }
3483

    
3484
    @Override
3485
    @SuppressWarnings("CloneDoesntCallSuperClone")
3486
    public Object clone() throws CloneNotSupportedException {
3487

    
3488
        DataStoreParameters dsp = getParameters();
3489

    
3490
        DefaultFeatureStore cloned_store = null;
3491

    
3492
        try {
3493
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3494
                    openStore(this.getProviderName(), dsp);
3495
            if (transforms != null) {
3496
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3497
                cloned_store.transforms.setStoreForClone(cloned_store);
3498
            }
3499
        } catch (Exception e) {
3500
            throw new CloneException(e);
3501
        }
3502
        return cloned_store;
3503

    
3504
    }
3505

    
3506
    @Override
3507
    public Feature getFeature(DynObject dynobject) {
3508
        if (dynobject instanceof DynObjectFeatureFacade) {
3509
            Feature f = ((DynObjectFeatureFacade) dynobject).getFeature();
3510
            return f;
3511
        }
3512
        return null;
3513
    }
3514

    
3515
    @Override
3516
    public Iterator iterator() {
3517
        FeatureSet fset = null;
3518
        try {
3519
            fset = this.getFeatureSet();
3520
            return fset.fastIterator();
3521
        } catch (DataException ex) {
3522
            throw new RuntimeException(ex);
3523
        } finally {
3524
            DisposeUtils.disposeQuietly(fset);
3525
        }
3526
    }
3527

    
3528
    @Override
3529
    public long size64() {
3530
        FeatureSet fset = null;
3531
        try {
3532
            fset = this.getFeatureSet();
3533
            return fset.getSize();
3534
        } catch (DataException ex) {
3535
            throw new RuntimeException(ex);
3536
        } finally {
3537
            DisposeUtils.disposeQuietly(fset);
3538
        }
3539
    }
3540

    
3541
    @Override
3542
    public ExpressionBuilder createExpressionBuilder() {
3543
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3544
        return builder;
3545
    }
3546

    
3547
    @Override
3548
    public ExpressionBuilder createExpression() {
3549
        return createExpressionBuilder();
3550
    }
3551

    
3552
    public FeatureSet features() throws DataException {
3553
        // This is to avoid jython to create a property with this name
3554
        // to access method getFeatures.
3555
        return this.getFeatureSet();
3556
    }
3557

    
3558
    @Override
3559
    public DataStoreProviderFactory getProviderFactory() {
3560
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3561
        return factory;
3562
    }
3563

    
3564
    @Override
3565
    public void useCache(String providerName, DynObject parameters) throws DataException {
3566
        throw new UnsupportedOperationException();
3567
    }
3568

    
3569
    @Override
3570
    public boolean isBroken() {
3571
        return this.state.isBroken();
3572
    }
3573

    
3574
    @Override
3575
    public Throwable getBreakingsCause() {
3576
        return this.state.getBreakingsCause();
3577
    }
3578

    
3579
    @Override
3580
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3581
        FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3582
        if (!factory.supportNumericOID()) {
3583
            return null;
3584
        }
3585
        SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3586
        return wrappedIndex;
3587
    }
3588

    
3589
    @Override
3590
    public FeatureReference getFeatureReference(String code) {
3591
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3592
        return featureReference;
3593
    }
3594

    
3595
    @Override
3596
    public long getPendingChangesCount() {
3597
        if (this.featureManager == null) {
3598
            return 0;
3599
        }
3600
        return this.featureManager.getPendingChangesCount();
3601
    }
3602

    
3603
    private ResourcesStorage resourcesStorage;
3604

    
3605
    @Override
3606
    public ResourcesStorage getResourcesStorage() {
3607
        if (this.resourcesStorage != null) {
3608
            return this.resourcesStorage;
3609
        }
3610
        ResourcesStorage theResourcesStorage;
3611
        try {
3612
            theResourcesStorage = this.provider.getResourcesStorage();
3613
            if (theResourcesStorage != null) {
3614
                this.resourcesStorage = theResourcesStorage;
3615
                return theResourcesStorage;
3616
            }
3617
        } catch (Throwable th) {
3618

    
3619
        }
3620
        try {
3621
            DataServerExplorer explorer = this.getExplorer();
3622
            if (explorer == null) {
3623
                return null;
3624
            }
3625
            theResourcesStorage = explorer.getResourcesStorage(this);
3626
            explorer.dispose();
3627
            this.resourcesStorage = theResourcesStorage;
3628
            return theResourcesStorage;
3629
        } catch (Exception ex) {
3630
            LOGGER.trace("Can't create resources storage", ex);
3631
            return null;
3632
        }
3633
    }
3634

    
3635
    @Override
3636
    public StoresRepository getStoresRepository() {
3637
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3638
        StoresRepository localRepository = this.provider.getStoresRepository();
3639
        if (localRepository == null) {
3640
            return mainRepository;
3641
        }
3642
        StoresRepository repository = new BaseStoresRepository(this.getName());
3643
        repository.addRepository(localRepository);
3644
        repository.addRepository(mainRepository);
3645
        return repository;
3646
    }
3647

    
3648
    @Override
3649
    public Feature getSampleFeature() {
3650
        if( sampleFeatureCache==null )  {
3651
            this.sampleFeatureCache = new CachedValue<Feature>(sample_feature_cache_timeout_ms) {
3652
                @Override
3653
                protected void reload() {
3654
                    Feature sampleFeature;
3655
                    long t1 = System.currentTimeMillis();
3656
                    try {                        
3657
                        FeatureSelection theSelection = getFeatureSelection();
3658
                        if (theSelection != null && !theSelection.isEmpty()) {
3659
                            sampleFeature = theSelection.first();
3660
                        } else {
3661
                            sampleFeature = first();
3662
                        }
3663
                        if (sampleFeature == null) {
3664
                            sampleFeature = createNewFeature();
3665
                        }
3666
                    } catch (DataException ex) {
3667
                        sampleFeature = null;
3668
                    }
3669
                    long t2 = System.currentTimeMillis();
3670
                    if( (t2 - t1)>5000 ) {
3671
                        // Mas de 5 seg es muy costoso, subimos mucho el tiempo de cache.
3672
                        this.setExpireTime(((60*60)*2)*1000); // 2h
3673
                    }
3674
                    this.setValue(sampleFeature);
3675
                }
3676
            };
3677
        }
3678
        return this.sampleFeatureCache.get();
3679
    }
3680

    
3681
    @Override
3682
    public boolean supportReferences() {
3683
        try {
3684
            return this.getDefaultFeatureType().supportReferences();
3685
        } catch (Exception ex) {
3686
            return false;
3687
        }
3688
    }
3689

    
3690
    @Override
3691
    public boolean isTemporary() {
3692
        if (this.provider == null) {
3693
            return true;
3694
        }
3695
        return this.provider.isTemporary();
3696
    }
3697

    
3698
    public FeatureType getOriginalFeatureType(FeatureType featureType) {
3699
        // FIXME this don't work for Store.fType.size() > 1
3700
        FeatureTypeManager manager = this.featureTypeManager;
3701
        if (manager == null) {
3702
            return null;
3703
        }
3704
        FeatureType originalFeatureType = manager.getOriginalFeatureType();
3705
        if (originalFeatureType == null) {
3706
            return null;
3707
        }
3708
        return originalFeatureType.getCopy();
3709
    }
3710

    
3711
    @Override
3712
    public Object getProperty(String name) {
3713
        if (this.propertiesSupportHelper == null) {
3714
            return null;
3715
        }
3716
        return this.propertiesSupportHelper.getProperty(name);
3717
    }
3718

    
3719
    @Override
3720
    public void setProperty(String name, Object value) {
3721
        if (this.propertiesSupportHelper == null) {
3722
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3723
        }
3724
        this.propertiesSupportHelper.setProperty(name, value);
3725
    }
3726

    
3727
    @Override
3728
    public Map<String, Object> getProperties() {
3729
        if (this.propertiesSupportHelper == null) {
3730
            return Collections.EMPTY_MAP;
3731
        }
3732
        return this.propertiesSupportHelper.getProperties();
3733
    }
3734

    
3735
    @Override
3736
    public Feature getOriginalFeature(FeatureReference id) {
3737
        if (this.featureManager == null) {
3738
            return null;
3739
        }
3740
        return featureManager.getOriginal(id);
3741
    }
3742

    
3743
    @Override
3744
    public Feature getOriginalFeature(Feature feature) {
3745
        if (feature == null) {
3746
            return null;
3747
        }
3748
        return getOriginalFeature(feature.getReference());
3749
    }
3750

    
3751
    @Override
3752
    public boolean isFeatureModified(FeatureReference id) {
3753
        if (this.featureManager == null) {
3754
            return false;
3755
        }
3756
        return featureManager.isFeatureModified(id);
3757
    }
3758

    
3759
    @Override
3760
    public boolean isFeatureModified(Feature feature) {
3761
        if (feature == null) {
3762
            return false;
3763
        }
3764
        return isFeatureModified(feature.getReference());
3765
    }
3766

    
3767
    @Override
3768
    public void setTransaction(DataTransaction transaction) {
3769
        this.transaction = transaction;
3770
        if (transaction instanceof DataTransactionServices) {
3771
            this.provider.setTransaction((DataTransactionServices) transaction);
3772
        }
3773
    }
3774

    
3775
    @Override
3776
    public DataTransaction getTransaction() {
3777
        return transaction;
3778
    }
3779

    
3780
    @Override
3781
    public String toString() {
3782
        try {
3783
            return String.format("%s %x %s", this.getClass().getSimpleName(), this.hashCode(), this.getFullName());
3784
        } catch (Exception e) {
3785
            return super.toString();
3786
        }
3787
    }
3788

    
3789
    public String createUniqueID() {
3790
        UUID x = UUID.randomUUID();
3791
        String s = x.toString();
3792
        return s;
3793
    }
3794

    
3795
    @Override
3796
    public List<FeatureReference> getEditedFeatures() {
3797
        if( this.featureManager == null ) {
3798
            return Collections.EMPTY_LIST;
3799
        }
3800
        List<FeatureReference> references = this.featureManager.getAddedAndUpdatedFeatures();
3801
        if( references==null ) {
3802
            return Collections.EMPTY_LIST;
3803
        }
3804
        return references;
3805
    }
3806
    
3807
    public List<FeatureReference> getEditedFeaturesNotValidated() {
3808

    
3809
        try {
3810
            if (this.featureManager == null) {
3811
                return Collections.EMPTY_LIST;
3812
            }
3813
            
3814
            FeatureType type = this.getDefaultFeatureTypeQuietly();
3815
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
3816
            
3817
//            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS | CHECK_BASIC : 0;
3818
            int checks = CHECK_REQUIREDS | CHECK_BASIC;
3819
            if(type.isCheckFeaturesAtFinishEditing()){
3820
                checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
3821
            }
3822
            if (checks == 0) {
3823
                return Collections.EMPTY_LIST;
3824
            }
3825
            List<FeatureReference> references = this.featureManager
3826
                    .getAddedAndUpdatedFeaturesNotValidated(rules, checks);
3827
            if (references == null) {
3828
                return Collections.EMPTY_LIST;
3829
            }
3830
            return references;
3831
        } catch (DataException ex) {
3832
            return null;
3833
        }
3834

    
3835
    }
3836

    
3837
    public Iterator<Feature> getFeaturesIterator(Iterator<FeatureReference> references) {
3838
        return new FeatureReferenceIteratorToFeatureIterator(this, references);
3839
    }
3840

    
3841
    public boolean isFeatureSelectionAvailable() {
3842
        try {
3843
            FeatureType type = this.getDefaultFeatureType();
3844
            return type.supportReferences();
3845
        } catch (DataException ex) {
3846
            return false;
3847
        }
3848
    }
3849
}