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

History | View | Annotate | Download (134 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.featureset.DefaultFeatureSet;
130
import org.gvsig.fmap.dal.feature.impl.undo.DefaultFeatureCommandsStack;
131
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
132
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
133
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
134
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
135
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
136
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
137
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
138
import org.gvsig.fmap.dal.feature.spi.cache.FeatureCacheProvider;
139
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProviderServices;
140
import org.gvsig.fmap.dal.impl.DefaultDataManager;
141
import org.gvsig.fmap.dal.resource.Resource;
142
import org.gvsig.fmap.dal.spi.AbstractDataStore;
143
import org.gvsig.fmap.dal.spi.DataStoreInitializer2;
144
import org.gvsig.fmap.dal.spi.DataStoreProvider;
145
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
146
import org.gvsig.fmap.dal.spi.DataTransactionServices;
147
import org.gvsig.fmap.geom.Geometry;
148
import org.gvsig.fmap.geom.SpatialIndex;
149
import org.gvsig.fmap.geom.primitive.Envelope;
150
import org.gvsig.metadata.MetadataLocator;
151
import org.gvsig.metadata.MetadataManager;
152
import org.gvsig.metadata.exceptions.MetadataException;
153
import org.gvsig.timesupport.Interval;
154
import org.gvsig.tools.ToolsLocator;
155
import org.gvsig.tools.dispose.DisposableIterator;
156
import org.gvsig.tools.dispose.DisposeUtils;
157
import org.gvsig.tools.dynobject.DelegatedDynObject;
158
import org.gvsig.tools.dynobject.DynClass;
159
import org.gvsig.tools.dynobject.DynObject;
160
import org.gvsig.tools.dynobject.DynObjectManager;
161
import org.gvsig.tools.dynobject.DynObject_v2;
162
import org.gvsig.tools.dynobject.DynStruct;
163
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
164
import org.gvsig.tools.dynobject.exception.DynMethodException;
165
import org.gvsig.tools.exception.BaseException;
166
import org.gvsig.tools.exception.NotYetImplemented;
167
import org.gvsig.tools.identitymanagement.SimpleIdentityManager;
168
import org.gvsig.tools.observer.Observable;
169
import org.gvsig.tools.observer.Observer;
170
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
171
import org.gvsig.tools.persistence.PersistenceManager;
172
import org.gvsig.tools.persistence.Persistent;
173
import org.gvsig.tools.persistence.PersistentState;
174
import org.gvsig.tools.persistence.exception.PersistenceException;
175
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
176
import org.gvsig.tools.undo.RedoException;
177
import org.gvsig.tools.undo.UndoException;
178
import org.gvsig.tools.undo.command.Command;
179
import org.gvsig.tools.util.CachedValue;
180
import org.gvsig.tools.util.ChainedIterator;
181
import org.gvsig.tools.util.GetItemWithSizeIsEmptyAndIterator64;
182
import org.gvsig.tools.util.HasAFile;
183
import org.gvsig.tools.util.PropertiesSupportHelper;
184
import org.gvsig.tools.util.UnmodifiableBasicMap;
185
import org.gvsig.tools.visitor.VisitCanceledException;
186
import org.gvsig.tools.visitor.Visitor;
187

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

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

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

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

    
204
    private FeatureCommandsStack commands;
205

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

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

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

    
221
    private DefaultDataManager dataManager = null;
222

    
223
    private FeatureStoreProvider provider = null;
224

    
225
    private DefaultFeatureIndexes indexes;
226

    
227
    private DefaultFeatureStoreTransforms transforms;
228

    
229
    /*friend*/ DelegatedDynObject metadata;
230

    
231
    private Set metadataChildren;
232

    
233
    private Long featureCount = null;
234

    
235
    private long temporalOid = 0;
236

    
237
    private FeatureCacheProvider cache;
238

    
239
    private final StateInformation state;
240

    
241
    private FeatureStoreTimeSupport timeSupport;
242

    
243
    private PropertiesSupportHelper propertiesSupportHelper;
244
    private DataTransaction transaction;
245

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

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

    
252
        private static final long serialVersionUID = 4109026189635185666L;
253

    
254
        private boolean broken;
255
        private Throwable breakingsCause;
256

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

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

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

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

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

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

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

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

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

    
311
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
312

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

    
318
        this.dataManager = (DefaultDataManager) dataManager;
319

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

    
328
    }
329

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
637
        }
638

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

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

    
646
    }
647

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

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

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

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

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

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

    
760
                }
761

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
938
    }
939

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1065
    }
1066

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

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

    
1076
    }
1077

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

    
1082
    }
1083

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

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

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

    
1102
    }
1103

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

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

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

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

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

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

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

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

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

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

    
1181
        }
1182

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

    
1187
        featureCount = null;
1188

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

    
1193
        this.editingSessionCode = null;
1194
    }
1195

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1428
        }
1429
    }
1430

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

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

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

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

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

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

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

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

    
1531
    private static EditableFeature lastChangedFeature = null;
1532

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

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

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

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

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

    
1588
        waitForIndexes();
1589

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2005
    }
2006

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

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

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

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

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

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

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

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

    
2146
            case MODE_APPEND:
2147
                return true;
2148

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

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

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

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

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

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

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

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

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

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

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

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

    
2267
    }
2268

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2709
        }
2710

    
2711
        return type;
2712
    }
2713

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

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

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

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

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

    
2755
            return avoidEditable(defaultFeatureType);
2756

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

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

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

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

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

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

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

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

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

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

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

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

    
2892
    }
2893

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3256
    }
3257

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

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

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

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

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

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

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

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

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

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

    
3348
        featureCount = null;
3349
    }
3350

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

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

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

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

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

    
3399
    }
3400

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

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

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

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

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

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

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

    
3480
        this.timeSupport = timeSupport;
3481
    }
3482

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

    
3487
        DataStoreParameters dsp = getParameters();
3488

    
3489
        DefaultFeatureStore cloned_store = null;
3490

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

    
3503
    }
3504

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3602
    private ResourcesStorage resourcesStorage;
3603

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3834
    }
3835

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

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