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

History | View | Annotate | Download (143 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.impl;
25

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

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

    
202
    public static long sample_feature_cache_timeout_ms = 15000;
203
    
204
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
205

    
206
    private DataStoreParameters parameters = null;
207
    private FeatureSelection selection;
208
    private FeatureLocks locks;
209

    
210
    private DelegateWeakReferencingObservable delegateObservable
211
            = new DelegateWeakReferencingObservable(this);
212

    
213
    private FeatureCommandsStack commands;
214

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

    
222
    private FeatureType defaultFeatureType = null;
223
    private List<FeatureType> featureTypes = new ArrayList<>();
224

    
225
    private int mode = MODE_QUERY;
226
    private int lastMode = MODE_QUERY;
227
    
228
    private long versionOfUpdate = 0;
229
    private boolean hasStrongChanges = true;
230

    
231
    private DefaultDataManager dataManager = null;
232

    
233
    private FeatureStoreProvider provider = null;
234

    
235
    private DefaultFeatureIndexes indexes;
236

    
237
    private DefaultFeatureStoreTransforms transforms;
238

    
239
    /*friend*/ DelegatedDynObject metadata;
240

    
241
    private Set metadataChildren;
242

    
243
    private Long featureCount = null;
244

    
245
    private long temporalOid = 0;
246

    
247
    private FeatureCacheProvider cache;
248

    
249
    private final StateInformation state;
250

    
251
    private FeatureStoreTimeSupport timeSupport;
252

    
253
    private PropertiesSupportHelper propertiesSupportHelper;
254
    private DataTransaction transaction;
255

    
256
    private String editingSessionCode;
257
    private String lastEditingSessionCode;
258
    
259
    private CachedValue<Feature> sampleFeatureCache;
260
    
261
    private final Observer transactionObserver;
262
    private String fullNameForTraces;
263

    
264
    private class StateInformation extends HashMap<Object, Object> {
265

    
266
        private static final long serialVersionUID = 4109026189635185666L;
267

    
268
        private boolean broken;
269
        private Throwable breakingsCause;
270

    
271
        @SuppressWarnings("OverridableMethodCallInConstructor")
272
        public StateInformation() {
273
            this.clear();
274
        }
275

    
276
        @Override
277
        public void clear() {
278
            this.broken = false;
279
            this.breakingsCause = null;
280
            super.clear();
281
        }
282

    
283
        public boolean isBroken() {
284
            return this.broken;
285
        }
286

    
287
        public void broken() {
288
            this.broken = true;
289
        }
290

    
291
        public Throwable getBreakingsCause() {
292
            return this.breakingsCause;
293
        }
294

    
295
        public void setBreakingsCause(Throwable cause) {
296
            if (this.breakingsCause == null) {
297
                this.breakingsCause = cause;
298
            }
299
            this.broken = true;
300
        }
301
    }
302

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

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

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

    
333
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
334

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

    
340
        this.dataManager = (DefaultDataManager) dataManager;
341

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

    
350
    }
351

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
687
        }
688

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

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

    
696
    }
697

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

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

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

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

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

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

    
810
                }
811

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

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

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

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

    
844
        LOGGER.debug("load() broken:{}, {}, {}.",
845
                new Object[]{state.isBroken(), this.getProviderName(), params.toString((Object... args) -> StringUtils.equalsIgnoreCase((CharSequence) args[0], "password")?"******":args[1])}
846
        );
847
    }
848

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1024
    }
1025

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

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

    
1040
    @Override
1041
    public FeatureSelection getFeatureSelectionQuietly() {
1042
        try {
1043
            return this.getFeatureSelection();
1044
        } catch (DataException ex) {
1045
            return FeatureSelection.EMTPY_FEATURE_SELECTION;
1046
        }
1047
    }
1048
    
1049
    
1050

    
1051
    @Override
1052
    public boolean isFeatureSelectionEmpty() {
1053
        if( selection == null ) {
1054
            return true;
1055
        }
1056
        return selection.isEmpty();
1057
    }
1058
    
1059
    //
1060
    // ====================================================================
1061
    // Gestion de notificaciones
1062
    //
1063
    @Override
1064
    public FeatureStoreNotification notifyChange(FeatureStoreNotification storeNotification) {
1065
        if (delegateObservable != null) {
1066
            try {
1067
                delegateObservable.notifyObservers(storeNotification);
1068
            } catch (Throwable ex) {
1069
                LOGGER.warn("Problems notifying changes in the store '" + this.getName() + " (" + storeNotification.getType() + ").", ex);
1070
            }
1071
        }
1072
        return storeNotification;
1073
    }
1074

    
1075
    @Override
1076
    public FeatureStoreNotification notifyChange(String notification) {
1077
        return notifyChange(
1078
                new DefaultFeatureStoreNotification(
1079
                        this, notification, 
1080
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1081
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode
1082
                )
1083
        );
1084
    }
1085

    
1086
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode) {
1087
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode));
1088
    }
1089

    
1090
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode, int editMode) {
1091
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode, editMode));
1092
    }
1093

    
1094
    public FeatureStoreNotification notifyChange(String notification,
1095
//            String editingSessionCode,
1096
            Iterator<FeatureReference> deleteds,
1097
            Iterator<EditableFeature> inserteds,
1098
            Iterator<EditableFeature> updateds,
1099
            Iterator<FeatureTypeChanged> featureTypesChanged,
1100
            boolean isSelectionCompromised) {
1101
        return notifyChange(
1102
                new DefaultFeatureStoreNotification(
1103
                        this, notification, 
1104
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1105
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1106
                        deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised
1107
                )
1108
        );
1109
    }
1110

    
1111
    @Override
1112
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
1113
        Feature f = null;
1114
        if (data != null) {
1115
            try {
1116
                f = createFeature(data);
1117
            } catch (Throwable ex) {
1118
                LOGGER.warn("Problems creating a feature to notifying changes in the store '" + this.getName() + " (" + notification + ").", ex);
1119
            }
1120
        }
1121
        return notifyChange(notification, f);
1122
    }
1123

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

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

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

    
1157
    public FeatureStoreNotification notifyChange(String notification, EditableFeatureType type) {
1158
        return notifyChange(
1159
                new DefaultFeatureStoreNotification(
1160
                        this, notification, 
1161
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1162
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1163
                        type
1164
                )
1165
        );
1166
    }
1167

    
1168
    @Override
1169
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
1170
        return notifyChange(
1171
                new DefaultFeatureStoreNotification(
1172
                        this, DataStoreNotification.RESOURCE_CHANGED
1173
                )
1174
        );
1175
    }
1176

    
1177
    //
1178
    // ====================================================================
1179
    // Gestion de bloqueos
1180
    //
1181
    @Override
1182
    public boolean isLocksSupported() {
1183
        return this.provider.isLocksSupported();
1184
    }
1185

    
1186
    @Override
1187
    public FeatureLocks getLocks() throws DataException {
1188
        if (!this.provider.isLocksSupported()) {
1189
            LOGGER.warn("Locks not supported");
1190
            return null;
1191
        }
1192
        if (locks == null) {
1193
            this.locks = this.provider.createFeatureLocks();
1194
        }
1195
        return locks;
1196
    }
1197

    
1198
    //
1199
    // ====================================================================
1200
    // Interface Observable
1201
    //
1202
    @Override
1203
    public void disableNotifications() {
1204
        this.delegateObservable.disableNotifications();
1205

    
1206
    }
1207

    
1208
    @Override
1209
    public void enableNotifications() {
1210
        this.delegateObservable.enableNotifications();
1211
    }
1212

    
1213
    @Override
1214
    public void beginComplexNotification() {
1215
        this.delegateObservable.beginComplexNotification();
1216

    
1217
    }
1218

    
1219
    @Override
1220
    public void endComplexNotification() {
1221
        this.delegateObservable.endComplexNotification();
1222

    
1223
    }
1224

    
1225
    @Override
1226
    public void addObserver(Observer observer) {
1227
        if (delegateObservable != null) {
1228
            this.delegateObservable.addObserver(observer);
1229
        }
1230
    }
1231

    
1232
    @Override
1233
    public void deleteObserver(Observer observer) {
1234
        if (delegateObservable != null) {
1235
            this.delegateObservable.deleteObserver(observer);
1236
        }
1237
    }
1238

    
1239
    @Override
1240
    public void deleteObservers() {
1241
        this.delegateObservable.deleteObservers();
1242

    
1243
    }
1244

    
1245
    //
1246
    // ====================================================================
1247
    // Interface Observer
1248
    //
1249
    // Usado para observar:
1250
    // - su seleccion
1251
    // - sus bloqueos
1252
    // - sus recursos
1253
    //
1254
    @Override
1255
    public void update(Observable observable, Object notification) {
1256
        if (observable instanceof FeatureSet) {
1257
            if (observable == this.selection) {
1258
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1259
            } else if (observable == this.locks) {
1260
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1261
            }
1262

    
1263
        } else if (observable instanceof FeatureStoreProvider) {
1264
            if (observable == this.provider) {
1265

    
1266
            }
1267
        } else if (observable instanceof FeatureReferenceSelection) {
1268
            if (notification instanceof String) {
1269
                this.notifyChange((String) notification);
1270
            }
1271
        }
1272
    }
1273

    
1274
    //
1275
    // ====================================================================
1276
    // Edicion
1277
    //
1278
    private void newVersionOfUpdate() {
1279
        this.versionOfUpdate++;
1280
    }
1281

    
1282
    private long currentVersionOfUpdate() {
1283
        return this.versionOfUpdate;
1284
    }
1285

    
1286
    private void checkInEditingMode() throws NeedEditingModeException {
1287
        if (mode != MODE_FULLEDIT) {
1288
            throw new NeedEditingModeException(this.getName());
1289
        }
1290
    }
1291

    
1292
    private void checkNotInAppendMode() throws IllegalStateException {
1293
        if (mode == MODE_APPEND) {
1294
            throw new IllegalStateException("Error: store "
1295
                    + this.getFullName() + " is in append mode");
1296
        }
1297
    }
1298

    
1299
    private void checkIsOwnFeature(Feature feature)
1300
            throws IllegalFeatureException {
1301
        if (((DefaultFeature) feature).getStore() != this) {
1302
            throw new IllegalFeatureException(this.getName());
1303
        }
1304
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1305
        // fixFeatureType((DefaultFeatureType) feature.getType());
1306
    }
1307

    
1308
    private void exitEditingMode() {
1309
        if (commands != null) {
1310
            try {
1311
                commands.clear();
1312
            } catch (Exception ex) {
1313
                LOGGER.trace("Can't clear commands", ex);
1314
            }
1315
            commands = null;
1316
        }
1317

    
1318
        if (featureTypeManager != null) {
1319
            DisposeUtils.disposeQuietly(featureTypeManager);
1320
            featureTypeManager = null;
1321

    
1322
        }
1323

    
1324
        // TODO implementar un dispose para estos dos
1325
        featureManager = null;
1326
        spatialManager = null;
1327

    
1328
        featureCount = null;
1329

    
1330
        this.lastMode = this.mode;
1331
        mode = MODE_QUERY;
1332
        hasStrongChanges = true; // Lo deja a true por si las moscas
1333

    
1334
        this.lastEditingSessionCode = this.editingSessionCode;
1335
        this.editingSessionCode = null;
1336
        
1337
        if( StringUtils.equalsIgnoreCase(DatabaseWorkspaceManager.TABLE_RESOURCES_NAME, this.getName()) ) {
1338
            // Es un poco drastico, pero cuando terminamos edicion de la tabla
1339
            // GVSIGD_RESOURCES, borraremos las cache de todos los recursos por
1340
            // que no sabemos si se ha modificado alguno y ha quedado obsoleto.
1341
            DALLocator.getDataManager().clearAllCachedResources();
1342
        }
1343
    }
1344

    
1345
    @Override
1346
    synchronized public void edit() throws DataException {
1347
        edit(MODE_FULLEDIT);
1348
    }
1349

    
1350
    @Override
1351
    synchronized public void edit(int mode) throws DataException {
1352
        LOGGER.debug("Starting editing in mode: {}", mode);
1353
        if (this.mode != MODE_QUERY) {
1354
            throw new AlreadyEditingException(this.getName());
1355
        }
1356
        FeatureType ftype = this.getDefaultFeatureType();
1357
        String newSessionCode = this.createUniqueID();
1358
        try {
1359
            if (!this.provider.supportsAppendMode()) {
1360
                mode = MODE_FULLEDIT;
1361
            }
1362
            if (!this.canBeEdited()) {
1363
                 throw new IllegalStateException(this.getName());
1364
            }
1365
            switch (mode) {
1366
                case MODE_QUERY:
1367
                    throw new IllegalStateException(this.getName());
1368

    
1369
                case MODE_FULLEDIT:
1370
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1371
                            newSessionCode, mode).isCanceled()) {
1372
                        return;
1373
                    }
1374
                    this.editingSessionCode = newSessionCode;
1375
                    invalidateIndexes();
1376
                    featureManager = new FeatureManager(this);
1377
                    featureTypeManager = new FeatureTypeManager(this);
1378
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
1379

    
1380
                    commands = new DefaultFeatureCommandsStack(
1381
                            this, featureManager,
1382
                            spatialManager, featureTypeManager);
1383
                    this.mode = MODE_FULLEDIT;
1384
                    hasStrongChanges = false;
1385
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING, newSessionCode, this.mode);
1386
                    break;
1387

    
1388
                case MODE_APPEND:
1389
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1390
                            newSessionCode, mode).isCanceled()) {
1391
                        return;
1392
                    }
1393
                    this.editingSessionCode = newSessionCode;
1394
                    invalidateIndexes();
1395
                    this.provider.beginAppend();
1396
                    this.mode = MODE_APPEND;
1397
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1398
                            newSessionCode, this.mode);
1399
                    break;
1400
                case MODE_PASS_THROUGH:
1401
                    if (!this.provider.supportsPassThroughMode()) {
1402
                        throw new IllegalStateException(this.getName());
1403
                    }
1404
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1405
                            newSessionCode, mode).isCanceled()) {
1406
                        return;
1407
                    }
1408
                    this.editingSessionCode = newSessionCode;
1409
                    invalidateIndexes();
1410
                    this.mode = MODE_PASS_THROUGH;
1411
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1412
                            newSessionCode, this.mode);
1413
                    break;
1414

    
1415
            }
1416
        } catch (Exception e) {
1417
            try {
1418
                if (this.mode != MODE_QUERY) {
1419
                    exitEditingMode();
1420
                }
1421
                notifyChange(FeatureStoreNotification.FAILED_STARTEDITING,
1422
                        newSessionCode, mode);
1423
            } catch (Throwable th) {
1424
                LOGGER.warn("Can't cleanup after error in start editing.", th);
1425
            }
1426
            throw new StoreEditException(e, this.getName());
1427
        }
1428
    }
1429

    
1430
    private void invalidateIndexes() {
1431
        setIndexesValidStatus(false);
1432
    }
1433

    
1434
    private void setIndexesValidStatus(boolean valid) {
1435
        FeatureIndexes theIndexes = getIndexes();
1436
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1437
                ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1438
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1439
            FeatureIndex index = (FeatureIndex) iterator.next();
1440
            if (index instanceof FeatureIndexProviderServices) {
1441
                FeatureIndexProviderServices indexServices
1442
                        = (FeatureIndexProviderServices) index;
1443
                indexServices.setValid(valid);
1444
            }
1445
        }
1446
    }
1447

    
1448
    private void updateIndexes() throws FeatureIndexException {
1449
        FeatureIndexes theIndexes = getIndexes();
1450
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1451
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1452
            FeatureIndex index = (FeatureIndex) iterator.next();
1453
            if (index instanceof FeatureIndexProviderServices) {
1454
                FeatureIndexProviderServices indexServices
1455
                        = (FeatureIndexProviderServices) index;
1456
                indexServices.fill(true, null);
1457
            }
1458
        }
1459
    }
1460

    
1461
    private void waitForIndexes() {
1462
        FeatureIndexes theIndexes = getIndexes();
1463
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1464
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1465
            FeatureIndex index = (FeatureIndex) iterator.next();
1466
            if (index instanceof FeatureIndexProviderServices) {
1467
                FeatureIndexProviderServices indexServices
1468
                        = (FeatureIndexProviderServices) index;
1469
                indexServices.waitForIndex();
1470
            }
1471
        }
1472
    }
1473

    
1474
    private void disposeIndexes() {
1475
        FeatureIndexes theIndexes = getIndexes();
1476
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1477
        if (theIndexes == null) {
1478
            return;
1479
        }
1480
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1481
            FeatureIndex index = (FeatureIndex) iterator.next();
1482
            if (index instanceof FeatureIndexProviderServices) {
1483
                FeatureIndexProviderServices indexServices
1484
                        = (FeatureIndexProviderServices) index;
1485
                indexServices.dispose();
1486
            }
1487
        }
1488
    }
1489

    
1490
    @Override
1491
    public boolean isEditing() {
1492
        return mode == MODE_FULLEDIT;
1493
    }
1494

    
1495
    @Override
1496
    public boolean isAppending() {
1497
        return mode == MODE_APPEND;
1498
    }
1499

    
1500
    @Override
1501
    synchronized public void update(EditableFeatureType type)
1502
            throws DataException {
1503
        try {
1504
            if (type == null) {
1505
                throw new NullFeatureTypeException(getName());
1506
            }
1507

    
1508
            switch (this.mode) {
1509
                case MODE_QUERY:
1510
                    if (type.hasOnlyMetadataChanges(this.defaultFeatureType)) {
1511
                        if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1512
                            return;
1513
                        }
1514
                        FeatureType theType = type.getNotEditableCopy();
1515
                        if (defaultFeatureType.getId().equals(theType.getId())) {
1516
                            defaultFeatureType = theType;
1517
                        }
1518
                        List newtypes = new ArrayList();
1519
                        for (FeatureType featureType : this.featureTypes) {
1520
                            if (featureType.getId().equals(theType.getId())) {
1521
                                newtypes.add(theType);
1522
                            } else {
1523
                                newtypes.add(featureType);
1524
                            }
1525
                        }
1526
                        this.featureTypes = newtypes;
1527
                        saveDALFile();
1528
                        notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1529
                    }
1530

    
1531
                    break;
1532
                case MODE_FULLEDIT:
1533
                    if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1534
                        return;
1535
                    }
1536
                    newVersionOfUpdate();
1537

    
1538
                    FeatureType oldt = type.getSource().getCopy();
1539
                    FeatureType newt = type.getCopy();
1540
                    commands.update(newt, oldt);
1541
                    hasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1542
                    notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1543
                    break;
1544
                case MODE_APPEND:
1545
                case MODE_PASS_THROUGH:
1546
                    throw new NeedEditingModeException(this.getName());
1547

    
1548
            }
1549
        } catch (Exception e) {
1550
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1551
        }
1552
    }
1553

    
1554
    @Override
1555
    public void delete(Feature feature) throws DataException {
1556
        switch (this.mode) {
1557
            case MODE_PASS_THROUGH:
1558
                checkIsOwnFeature(feature);
1559
                if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1560
                    return;
1561
                }
1562
                this.provider.passThroughDelete((FeatureReferenceProviderServices) feature.getReference());
1563
                notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1564
                break;
1565
            default:
1566
                this.commands.delete(feature);
1567
                break;
1568

    
1569
        }
1570
    }
1571

    
1572
    @Override
1573
    public void delete(String filter) {
1574
        if (StringUtils.isBlank(filter)) {
1575
            return;
1576
        }
1577
        this.delete(ExpressionUtils.createExpression(filter));
1578
    }
1579

    
1580
    @Override
1581
    public void delete(Expression filter) {
1582
        if (filter == null) {
1583
            return;
1584
        }
1585
        boolean pendingFinishEditing = false;
1586
        DisposableFeatureSetIterable features = null;
1587
        try {
1588
            switch (this.mode) {
1589
                case MODE_QUERY:
1590
                    pendingFinishEditing = true;
1591
                    this.edit();
1592
                    break;
1593
                case MODE_APPEND:
1594
                    throw new IllegalStateException("Delete not allowed in append mode.");
1595
                case MODE_FULLEDIT:
1596
                    break;
1597
                case MODE_PASS_THROUGH:
1598
                    if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, filter).isCanceled()) {
1599
                        return;
1600
                    }
1601
                    this.provider.passThroughDelete(filter);
1602
                    notifyChange(FeatureStoreNotification.AFTER_DELETE, filter);                    
1603
                    return;
1604
                default:
1605
                    throw new IllegalStateException("Mode " + this.mode + " not supported.");
1606
            }
1607

    
1608
            FeatureSet fset = this.getFeatureSet(filter);
1609
            features = fset.iterable();
1610
            for (Feature f : features) {
1611
                fset.delete(f);
1612
            }
1613
        } catch (DataException ex) {
1614
            throw new DataRuntimeException(ex.getFormatString(), ex.getMessageKey(), ex.getCode()) {
1615
            };
1616
        } catch (Exception ex) {
1617
            throw new RuntimeException("Can't delete features (" + filter.getPhrase() + ").", ex);
1618
        } finally {
1619
            if (pendingFinishEditing) {
1620
                this.finishEditingQuietly();
1621
            }
1622
            DisposeUtils.disposeQuietly(features);
1623
        }
1624
    }
1625

    
1626
    synchronized public void doDelete(Feature feature) throws DataException {
1627
        if (feature == null) {
1628
            throw new IllegalArgumentException("feature argument can't be null.");
1629
        }
1630
        try {
1631
            checkInEditingMode();
1632
            checkIsOwnFeature(feature);
1633
            if (feature instanceof EditableFeature && !((EditableFeature)feature).isUpdatable()) {
1634
                //La feature no est? persistida en disco
1635
                throw new StoreDeleteEditableFeatureException(getName());
1636
            }
1637
            if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1638
                return;
1639
            }
1640

    
1641
            //Update the featureManager and the spatialManager
1642
            featureManager.delete(feature);
1643
            spatialManager.deleteFeature(feature);
1644

    
1645
            newVersionOfUpdate();
1646
            hasStrongChanges = true;
1647
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1648
        } catch (Exception e) {
1649
            throw new StoreDeleteFeatureException(e, this.getName());
1650
        }
1651
    }
1652

    
1653
    @Override
1654
    public synchronized void insert(FeatureSet set) throws DataException {
1655
        switch (mode) {
1656
            case MODE_QUERY:
1657
                throw new NeedEditingModeException(this.getName());
1658

    
1659
            case MODE_APPEND:
1660
            case MODE_FULLEDIT:
1661
            case MODE_PASS_THROUGH:
1662
            try {
1663
                set.accept((Object obj) -> {
1664
                    EditableFeature ef = createNewFeature((Feature) obj);
1665
                    insert(ef);
1666
                });
1667
            } catch (BaseException ex) {
1668
                throw new StoreInsertFeatureException(ex, this.getName());
1669
            }
1670
            break;
1671
        }
1672
    }
1673

    
1674
    private static EditableFeature lastChangedFeature = null;
1675

    
1676
    @Override
1677
    public synchronized void insert(EditableFeature feature)
1678
            throws DataException {
1679
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1680
        try {
1681
            switch (mode) {
1682
                case MODE_QUERY:
1683
                    throw new NeedEditingModeException(this.getName());
1684

    
1685
                case MODE_APPEND:
1686
                    checkIsOwnFeature(feature);
1687
                    if (feature.isUpdatable()) {
1688
                        throw new NoNewFeatureInsertException(this.getName());
1689
                    }
1690
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1691
                        return;
1692
                    }
1693
                    this.featureCount = null;
1694
                    feature.validate(CHECK_RULES_AT_EDITING);
1695
                    provider.append(((DefaultEditableFeature) feature).getData());
1696
                    hasStrongChanges = true;
1697
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1698
                    break;
1699

    
1700
                case MODE_FULLEDIT:
1701
                    if (feature.isUpdatable()) {
1702
                        throw new NoNewFeatureInsertException(this.getName());
1703
                    }
1704
                    feature.validate(CHECK_RULES_AT_EDITING);
1705
                    commands.insert(feature);
1706
                    break;
1707

    
1708
                case MODE_PASS_THROUGH:
1709
                    checkIsOwnFeature(feature);
1710
                    if (feature.isUpdatable()) {
1711
                        throw new NoNewFeatureInsertException(this.getName());
1712
                    }
1713
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1714
                        return;
1715
                    }
1716
                    feature.validate(CHECK_RULES_AT_EDITING);
1717
                    this.provider.passThroughInsert(((DefaultEditableFeature) feature).getData());
1718
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1719
                    break;
1720
            }
1721
        } catch (Exception e) {
1722
            throw new StoreInsertFeatureException(e, this.getName());
1723
        }
1724
    }
1725

    
1726
    synchronized public void doInsert(EditableFeature feature)
1727
            throws DataException {
1728
        checkIsOwnFeature(feature);
1729

    
1730
        waitForIndexes();
1731

    
1732
        if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1733
            return;
1734
        }
1735
        newVersionOfUpdate();
1736
        if ((lastChangedFeature == null)
1737
                || (lastChangedFeature.getSource() != feature.getSource())) {
1738
            lastChangedFeature = feature;
1739
            feature.validate(CHECK_RULES_AT_EDITING);
1740
            lastChangedFeature = null;
1741
        }
1742
        //Update the featureManager and the spatialManager
1743
        ((DefaultFeature) feature).setInserted(true);
1744
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1745

    
1746
        featureManager.add(feature);
1747
        spatialManager.insertFeature(newFeature);
1748

    
1749
        hasStrongChanges = true;
1750
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1751
    }
1752

    
1753
    @Override
1754
    public void update(EditableFeature feature)
1755
            throws DataException {
1756
        switch (this.mode) {
1757
            case MODE_PASS_THROUGH:
1758
                checkIsOwnFeature(feature);
1759
                if (!feature.isUpdatable()) {
1760
                    throw new NoNewFeatureInsertException(this.getName());
1761
                }
1762
                if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1763
                    return;
1764
                }
1765
                feature.validate(CHECK_RULES_AT_EDITING);
1766
                this.provider.passThroughUpdate(((DefaultEditableFeature) feature).getData());
1767
                notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1768
                break;
1769
            case MODE_FULLEDIT:
1770
                if(!feature.getType().supportReferences()){
1771
                    throw new UnsupportedOperationException("Can't update store in full edit mode without references support.");
1772
                }
1773
                if (feature.isUpdatable()) {
1774
                    commands.update(feature, feature.getSource());
1775
                    return;
1776
                }
1777
                // FIXME: Deberiamos lanzar aqui un error en lugar de hacer el insert.
1778
                //        O lanzar un mensaje al log?
1779
                insert(feature);
1780
                break;
1781
            default:
1782
                throw new NeedEditingModeException(this.getName());
1783
        }
1784
    }
1785

    
1786
    @Override
1787
    public void update(Object... parameters) throws DataException {
1788
        if (parameters.length == 1) {
1789
            Object param0 = parameters[0];
1790
            if (param0 instanceof EditableFeature) {
1791
                this.update((EditableFeature) param0);
1792
            } else if (param0 instanceof EditableFeatureType) {
1793
                this.update((EditableFeatureType) param0);
1794
            } else {
1795
                throw new IllegalArgumentException("Type of first parameter isn't supported");
1796
            }
1797
            return;
1798
        }
1799

    
1800
        Expression filter = null;
1801
        long end = parameters.length;
1802
        if (parameters.length % 2 == 1) { //IMPAR
1803
            Object param = parameters[parameters.length - 1];
1804
            if (param != null) {
1805
                if (param instanceof Expression) {
1806
                    filter = (Expression) param;
1807
                } else {
1808
                    filter = ExpressionUtils.createExpression(param.toString());
1809
                }
1810
            }
1811
        } else {
1812
            end = parameters.length - 1;
1813
        }
1814

    
1815
        switch (this.mode) {
1816
            case MODE_PASS_THROUGH:
1817
                this.provider.passThroughUpdate(
1818
                        //                    this.getName(), 
1819
                        parameters,
1820
                        filter);
1821
                break;
1822
            case MODE_FULLEDIT:
1823
                FeatureSet set = this.getFeatureSet(filter);
1824
                DisposableIterator it = set.fastIterator();
1825
                while (it.hasNext()) {
1826
                    Feature feature = (Feature) it.next();
1827
                    EditableFeature ef = feature.getEditable();
1828
                    for (int i = 0; i < end; i += 2) {
1829
                        String name = (String) parameters[i];
1830
                        Object value = parameters[i + 1];
1831
                        ef.set(name, value);
1832
                    }
1833
                    set.update(ef);
1834
                }
1835
                DisposeUtils.disposeQuietly(it);
1836
                DisposeUtils.disposeQuietly(set);
1837
                break;
1838
            default:
1839
                throw new NeedEditingModeException(this.getName());
1840
        }
1841
    }
1842

    
1843
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1844
            throws DataException {
1845
        try {
1846
            checkInEditingMode();
1847
            checkIsOwnFeature(feature);
1848
            if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1849
                return;
1850
            }
1851
            newVersionOfUpdate();
1852
            if ((lastChangedFeature == null)
1853
                    || (lastChangedFeature.getSource() != feature.getSource())) {
1854
                lastChangedFeature = feature;
1855
                feature.validate(CHECK_RULES_AT_EDITING);
1856
                lastChangedFeature = null;
1857
            }
1858

    
1859
            //Update the featureManager and the spatialManager
1860
            Feature newf = feature.getNotEditableCopy();
1861
            featureManager.update(feature, oldFeature);
1862
            spatialManager.updateFeature(newf, oldFeature);
1863

    
1864
            hasStrongChanges = true;
1865
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1866
        } catch (Exception e) {
1867
            throw new StoreUpdateFeatureException(e, this.getName());
1868
        }
1869
    }
1870

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

    
1888
    @Override
1889
    synchronized public void undo() throws UndoException {
1890
        Command undo = commands.getNextUndoCommand();
1891
        try {
1892
            checkInEditingMode();
1893
        } catch (NeedEditingModeException ex) {
1894
            throw new UndoException(undo, ex);
1895
        }
1896
        if (notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled()) {
1897
            return;
1898
        }
1899
        newVersionOfUpdate();
1900
        commands.undo();
1901
        hasStrongChanges = true;
1902
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1903
    }
1904

    
1905
    @Override
1906
    public List getRedoInfos() {
1907
        if (isEditing() && (commands != null)) {
1908
            return commands.getRedoInfos();
1909
        } else {
1910
            return null;
1911
        }
1912
    }
1913

    
1914
    @Override
1915
    public List getUndoInfos() {
1916
        if (isEditing() && (commands != null)) {
1917
            return commands.getUndoInfos();
1918
        } else {
1919
            return null;
1920
        }
1921
    }
1922

    
1923
    public synchronized FeatureCommandsStack getCommandsStack()
1924
            throws DataException {
1925
        checkInEditingMode();
1926
        return commands;
1927
    }
1928

    
1929
    @Override
1930
    public boolean cancelEditingQuietly() {
1931
        try {
1932
            this.cancelEditing();
1933
            return true;
1934
        } catch (Exception ex) {
1935
            LOGGER.debug("Can't cancel editing", ex);
1936
            return false;
1937
        }
1938
    }
1939

    
1940
    @Override
1941
    synchronized public void cancelEditing() throws DataException {
1942
        if (spatialManager != null) {
1943
            spatialManager.cancelModifies();
1944
        }
1945
        try {
1946
            switch (mode) {
1947
                case MODE_QUERY:
1948
                    throw new NeedEditingModeException(this.getName());
1949

    
1950
                case MODE_APPEND:
1951
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1952
                        return;
1953
                    }
1954
                    provider.abortAppend();
1955
                    exitEditingMode();
1956
                    ((FeatureSelection) this.getSelection()).deselectAll();
1957
                    updateIndexes();
1958
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1959
                    break;
1960

    
1961
                case MODE_FULLEDIT:
1962
                    boolean clearSelection = this.hasStrongChanges;
1963
                    if (this.selection instanceof FeatureReferenceSelection) {
1964
                        clearSelection = this.hasStrongChanges || this.featureManager.hasNews();
1965
                    }
1966
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1967
                        return;
1968
                    }
1969
                    exitEditingMode();
1970
                    if (clearSelection) {
1971
                        ((FeatureSelection) this.getSelection()).deselectAll();
1972
                    }
1973
                    updateIndexes();
1974
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1975
                    break;
1976

    
1977
                case MODE_PASS_THROUGH:
1978
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1979
                        return;
1980
                    }
1981
                    exitEditingMode();
1982
                    ((FeatureSelection) this.getSelection()).deselectAll();
1983
                    updateIndexes();
1984
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1985
                    break;
1986
            }
1987
        } catch (Exception e) {
1988
            throw new StoreCancelEditingException(e, this.getName());
1989
        }
1990
    }
1991

    
1992
    @Override
1993
    public boolean finishEditingQuietly() {
1994
        try {
1995
            this.finishEditing();
1996
            return true;
1997
        } catch (Exception ex) {
1998
            LOGGER.debug("Can't finish editing", ex);
1999
            return false;
2000
        }
2001
    }
2002

    
2003
    @Override
2004
    synchronized public void finishEditing() throws DataException {
2005
        LOGGER.debug("finish editing of mode: {}", mode);
2006
        try {
2007
            Map<String, List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
2008
            switch (mode) {
2009
                case MODE_QUERY:
2010
                    throw new NeedEditingModeException(this.getName());
2011

    
2012
                case MODE_APPEND:
2013
                    if (selection != null) {
2014
                        selection = null;
2015
                    }
2016
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2017
                        return;
2018
                    }
2019
                    saveDALFile();
2020
                    provider.endAppend();
2021
                    exitEditingMode();
2022
                    this.updateComputedFields(computedFields);
2023
                    loadDALFile();
2024
                    updateIndexes();
2025
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2026
                    break;
2027

    
2028
                case MODE_FULLEDIT:
2029
                    if (featureManager.hasChanges() || featureTypeManager.hasChanges()) {
2030
                        if (hasStrongChanges && !this.allowWrite()) {
2031
                            throw new WriteNotAllowedException(getName());
2032
                        }
2033
                        if (notifyChange(FeatureStoreNotification.PREPARING_FINISHEDITING).isCanceled()) {
2034
                            return;
2035
                        }
2036
                        if (hasStrongChanges) {
2037
                            validateFeaturesAtFinishEditing();
2038
                        }
2039
                        if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING,
2040
                                featureManager.getDeleted(),
2041
                                featureManager.getInsertedFeatures(),
2042
                                featureManager.getUpdatedFeatures(),
2043
                                featureTypeManager.getFeatureTypesChanged().iterator(),
2044
                                featureManager.isSelectionCompromised()).isCanceled()) {
2045
                            return;
2046
                        }
2047
                        saveDALFile();
2048
                        if (featureManager.isSelectionCompromised() && selection != null) {
2049
                            selection = null;
2050
                        }
2051
                        if (hasStrongChanges) {
2052
                            // This will throw a PerformEditingException if the provider
2053
                            // does not accept the changes (for example, an invalid field name)
2054
                            provider.performChanges(featureManager.getDeleted(),
2055
                                    featureManager.getInserted(),
2056
                                    featureManager.getUpdated(),
2057
                                    removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2058

    
2059
                        }
2060
                        this.updateComputedFields(computedFields);
2061
                        exitEditingMode();
2062
                        loadDALFile();
2063
                        updateIndexes();
2064
                    } else {
2065
                        exitEditingMode();
2066
                    }
2067
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2068
                    break;
2069
                case MODE_PASS_THROUGH:
2070
                    if (selection != null) {
2071
                        selection = null;
2072
                    }
2073
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2074
                        return;
2075
                    }
2076
                    exitEditingMode();
2077
                    updateIndexes();
2078
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2079
                    break;
2080
            }
2081
        } catch (ValidateFeaturesException | WriteNotAllowedException ex) {
2082
            // Don't notify failed.
2083
            throw ex;
2084
        } catch (PerformEditingException pee) {
2085
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2086
            throw new WriteException(provider.getSourceId().toString(), pee);
2087
        } catch (Exception e) {
2088
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2089
            throw new FinishEditingException(e);
2090
        }
2091
    }
2092

    
2093
    @Override
2094
    public String getEditingSession() {
2095
        return this.editingSessionCode;
2096
    }
2097

    
2098
    private Map<String, List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
2099
        Map<String, List<FeatureAttributeDescriptor>> r = new HashMap<>();
2100

    
2101
        List<FeatureType> theTypes = new ArrayList<>();
2102
        theTypes.addAll(this.getFeatureTypes());
2103
        theTypes.add(this.getDefaultFeatureType());
2104
        for (int n = 0; n < theTypes.size(); n++) {
2105
            FeatureType type = theTypes.get(n);
2106
            for (FeatureAttributeDescriptor attrdesc : type) {
2107
                FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
2108
                if (emulator != null) {
2109
                    List<FeatureAttributeDescriptor> l = r.get(type.getId());
2110
                    if (l == null) {
2111
                        l = new ArrayList<>();
2112
                        r.put(type.getId(), l);
2113
                    }
2114
                    l.add(attrdesc);
2115
                }
2116
            }
2117
        }
2118
        return r;
2119
    }
2120

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

    
2123
        List<FeatureType> theTypes = new ArrayList<>();
2124
        theTypes.addAll(this.getFeatureTypes());
2125
        theTypes.add(this.getDefaultFeatureType());
2126
        for (int n = 0; n < theTypes.size(); n++) {
2127
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
2128
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
2129
            if (x != null && !x.isEmpty()) {
2130
                for (FeatureAttributeDescriptor attrdesc : x) {
2131
                    if (type.get(attrdesc.getName()) == null) {
2132
                        type.add(attrdesc);
2133
                    }
2134
                }
2135
            }
2136
        }
2137

    
2138
    }
2139

    
2140
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
2141
        // FIXME: Falta por implementar
2142
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
2143
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
2144
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
2145
//                if (attributeDescriptor.isComputed()) {
2146
//                    target.remove(attributeDescriptor.getName());
2147
//                }
2148
//            }
2149
//        }
2150
        return ftypes;
2151
    }
2152

    
2153
    private void clearResourcesCache() {
2154
        ResourcesStorage theResourcesStorage = null;
2155
        try {
2156
            theResourcesStorage = this.getResourcesStorage();
2157
            if (theResourcesStorage == null ) {
2158
                return;
2159
            }
2160
            theResourcesStorage.clearCache();
2161
        } catch (Throwable ex) {
2162
            LOGGER.warn("Can't clear resources for store '"+this.getFullNameForTraces()+"'.", ex);
2163
        } finally {
2164
            DisposeUtils.disposeQuietly(theResourcesStorage);
2165
        }
2166
    }
2167
    
2168
    private void saveDALFile() {
2169
        if( this.ignoreDALResource ) {
2170
            return;
2171
        }
2172
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2173
        ResourcesStorage theResourcesStorage = null;
2174
        try {
2175
            theResourcesStorage = this.getResourcesStorage();
2176
            if (theResourcesStorage == null || theResourcesStorage.isReadOnly()) {
2177
                return;
2178
            }
2179
            resource = theResourcesStorage.getResource("dal");
2180
            if (resource == null || resource.isReadOnly()) {
2181
                return;
2182
            }
2183
            DALFile dalFile = DALFile.getDALFile();
2184
            dalFile.setStore(this);
2185
            if (!dalFile.isEmpty()) {
2186
                dalFile.write(resource);
2187
            }
2188
        } catch (Throwable ex) {
2189
            LOGGER.warn("Can't save DAL resource", ex);
2190
        } finally {
2191
            IOUtils.closeQuietly(resource);
2192
            DisposeUtils.disposeQuietly(theResourcesStorage);
2193
        }
2194
    }
2195

    
2196
    private void loadDALFile() {
2197
        if( this.ignoreDALResource ) {
2198
            return;
2199
        }
2200
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2201
        ResourcesStorage theResourcesStorage = null;
2202
        try {
2203
            theResourcesStorage = this.getResourcesStorage();
2204
            if (theResourcesStorage == null) {
2205
                return;
2206
            }
2207
            resource = theResourcesStorage.getResource("dal");
2208
            if (resource == null || !resource.exists()) {
2209
                return;
2210
            }
2211
            DALFile dalFile = DALFile.getDALFile(resource);
2212
            if (!dalFile.isEmpty()) {
2213
                dalFile.updateStore(this);
2214
            }
2215
        } catch (Throwable ex) {
2216
            if (resource == null || theResourcesStorage == null) {
2217
                if (theResourcesStorage == null) {
2218
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=null)", ex);
2219
                } else {
2220
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2221
                }
2222
            } else {
2223
                LOGGER.warn("Can't load DAL resource (resname=" + resource.getName() + ", resurl=" + Objects.toString(resource.getURL()) + ", storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2224
            }
2225
        } finally {
2226
            IOUtils.closeQuietly(resource);
2227
            DisposeUtils.disposeQuietly(theResourcesStorage);
2228
        }
2229
    }
2230

    
2231
    /**
2232
     * Save changes in the provider without leaving the edit mode. Do not call
2233
     * observers to communicate a change of ediding mode. The operation's
2234
     * history is eliminated to prevent inconsistencies in the data.
2235
     *
2236
     * @throws DataException
2237
     */
2238
    @Override
2239
    synchronized public void commitChanges() throws DataException {
2240
        LOGGER.debug("commitChanges of mode: {}", mode);
2241
        if (!canCommitChanges()) {
2242
            throw new WriteNotAllowedException(getName());
2243
        }
2244
        try {
2245
            switch (mode) {
2246
                case MODE_QUERY:
2247
                    throw new NeedEditingModeException(this.getName());
2248

    
2249
                case MODE_APPEND:
2250
                    this.provider.endAppend();
2251
                    exitEditingMode();
2252
                    invalidateIndexes();
2253
                    this.provider.beginAppend();
2254
                    break;
2255

    
2256
                case MODE_FULLEDIT:
2257
                    if (hasStrongChanges && !this.allowWrite()) {
2258
                        throw new WriteNotAllowedException(getName());
2259
                    }
2260
                    // FIXME: OOhh!!!! no se disparan eventos, VCSGis no se entera de estos cambios.
2261
                    if (hasStrongChanges) {
2262
                        validateFeaturesAtFinishEditing();
2263
                        provider.performChanges(featureManager.getDeleted(),
2264
                                featureManager.getInserted(),
2265
                                featureManager.getUpdated(),
2266
                                removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2267
                    }
2268
                    invalidateIndexes();
2269
                    featureManager = new FeatureManager(this);
2270
                    featureTypeManager = new FeatureTypeManager(this);
2271
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
2272

    
2273
                    commands
2274
                            = new DefaultFeatureCommandsStack(this, featureManager,
2275
                                    spatialManager, featureTypeManager);
2276
                    featureCount = null;
2277
                    hasStrongChanges = false;
2278
                    break;
2279
            }
2280
        } catch (Exception e) {
2281
            throw new FinishEditingException(e);
2282
        }
2283
    }
2284

    
2285
    @Override
2286
    synchronized public boolean canCommitChanges() throws DataException {
2287
        if (!this.allowWrite()) {
2288
            return false;
2289
        }
2290
        switch (mode) {
2291
            default:
2292
            case MODE_QUERY:
2293
                return false;
2294

    
2295
            case MODE_APPEND:
2296
                return true;
2297

    
2298
            case MODE_FULLEDIT:
2299
                List types = this.getFeatureTypes();
2300
                for (int i = 0; i < types.size(); i++) {
2301
                    Object type = types.get(i);
2302
                    if (type instanceof DefaultEditableFeatureType) {
2303
                        if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
2304
                            return false;
2305
                        }
2306
                    }
2307
                }
2308
                return true;
2309
        }
2310
    }
2311

    
2312
    @Override
2313
    public void beginEditingGroup(String description)
2314
            throws NeedEditingModeException {
2315
        checkInEditingMode();
2316
        commands.startComplex(description);
2317
    }
2318

    
2319
    @Override
2320
    public void endEditingGroup() throws NeedEditingModeException {
2321
        checkInEditingMode();
2322
        commands.endComplex();
2323
    }
2324

    
2325
    @Override
2326
    public boolean isAppendModeSupported() {
2327
        return this.provider.supportsAppendMode();
2328
    }
2329

    
2330
    @Override
2331
    public void export(DataServerExplorer explorer, String provider,
2332
            NewFeatureStoreParameters params, String name) throws DataException {
2333

    
2334
        if (this.getFeatureTypes().size() != 1) {
2335
            throw new NotYetImplemented(
2336
                    "export whith more than one type not yet implemented");
2337
        }
2338
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2339
        FeatureStore target = null;
2340
        FeatureSet features = null;
2341
        DisposableIterator iterator = null;
2342
        try {
2343
            FeatureType type = this.getDefaultFeatureType();
2344
            if ((params.getDefaultFeatureType() == null)
2345
                    || (params.getDefaultFeatureType().size() == 0)) {
2346
                params.setDefaultFeatureType(type.getEditable());
2347

    
2348
            }
2349
            explorer.add(provider, params, true);
2350
            DataManager manager = DALLocator.getDataManager();
2351

    
2352
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2353
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2354

    
2355
            target = (FeatureStore) manager.openStore(provider, openParams);
2356
            FeatureType targetType = target.getDefaultFeatureType();
2357

    
2358
            target.edit(MODE_APPEND);
2359
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2360
            if (featureSelection.getSize() > 0) {
2361
                features = this.getFeatureSelection();
2362
            } else {
2363
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2364
                    FeatureQuery query = createFeatureQuery();
2365
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2366
                        query.getOrder().add(pkattr.getName(), true);
2367
                    }
2368
                    features = this.getFeatureSet(query);
2369
                } else {
2370
                    features = this.getFeatureSet();
2371
                }
2372
            }
2373
            iterator = features.fastIterator();
2374
            while (iterator.hasNext()) {
2375
                DefaultFeature feature = (DefaultFeature) iterator.next();
2376
                target.insert(target.createNewFeature(targetType, feature));
2377
            }
2378
            target.finishEditing();
2379
            target.dispose();
2380
        } catch (Exception e) {
2381
            throw new DataExportException(e, params.toString());
2382
        } finally {
2383
            dispose(iterator);
2384
            dispose(features);
2385
            dispose(target);
2386
        }
2387
    }
2388

    
2389
    @Override
2390
    public void copyTo(final FeatureStore target) {
2391
        boolean finishEditingAtEnd = false;
2392
        try {
2393
            if (!target.isEditing() && !target.isAppending()) {
2394
                finishEditingAtEnd = true;
2395
                target.edit(MODE_APPEND);
2396
            }
2397
            this.accept((Object obj) -> {
2398
                Feature f_src = (Feature) obj;
2399
                EditableFeature f_dst = target.createNewFeature(f_src);
2400
                target.insert(f_dst);
2401
            });
2402
            if (finishEditingAtEnd) {
2403
                target.finishEditing();
2404
            }
2405

    
2406
        } catch (Exception ex) {
2407
            try {
2408
                if (finishEditingAtEnd) {
2409
                    target.cancelEditing();
2410
                }
2411
            } catch (Exception ex1) {
2412
            }
2413
            throw new RuntimeException("Can't copy store.", ex);
2414
        }
2415

    
2416
    }
2417

    
2418
    //
2419
    // ====================================================================
2420
    // Obtencion de datos
2421
    // getDataCollection, getFeatureCollection
2422
    //
2423
    @Override
2424
    public DataSet getDataSet() throws DataException {
2425
        return this.getFeatureSet((FeatureQuery)null);
2426
    }
2427

    
2428
    @Override
2429
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2430
        return this.getFeatureSet((FeatureQuery)dataQuery);
2431
    }
2432

    
2433
    @Override
2434
    public void getDataSet(Observer observer) throws DataException {
2435
        checkNotInAppendMode();
2436
        this.getFeatureSet(null, observer);
2437
    }
2438

    
2439
    @Override
2440
    public void getDataSet(DataQuery dataQuery, Observer observer)
2441
            throws DataException {
2442
        checkNotInAppendMode();
2443
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2444
    }
2445

    
2446
    @Override
2447
    public FeatureSet getFeatureSet() throws DataException {
2448
        return this.getFeatureSet((FeatureQuery) null);
2449
    }
2450

    
2451
    @Override
2452
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2453
            throws DataException {
2454
        checkNotInAppendMode();
2455
        if (featureQuery == null) {
2456
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2457
        } else if( featureQuery.hasAggregateFunctions() || featureQuery.hasGroupByColumns() ) {
2458
            // Si tenemos datos por persistir en la bbdd (bien por que estamos en modo 
2459
            // append(batchsize) o por que estamos en modo fulledit y hay cambios
2460
            // realizados, las agrupaciones y funciones de agregado, como las gestiona
2461
            // la bbdd, pueden no dar resultados correctos. Asi que no dejamos hacer
2462
            // estas operaciones.
2463
            if( this.mode==MODE_APPEND  ) {
2464
                throw new UnsupportedOperationException("Can't create a set with aggregate functions or group by columns in append mode");
2465
            }
2466
            if( this.mode == MODE_FULLEDIT ) {
2467
                if( this.featureManager==null || this.featureManager.getPendingChangesCount()>0 ) {
2468
                   throw new UnsupportedOperationException("Can't create a set with aggregate functions or group by columns with editing changes");
2469
                }
2470
            }
2471
        }
2472
        return new DefaultFeatureSet(this, featureQuery);
2473
    }
2474

    
2475
    @Override
2476
    public FeatureSet getFeatureSet(String filter) throws DataException {
2477
        return this.getFeatureSet(filter, null, true);
2478
    }
2479

    
2480
    @Override
2481
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2482
        return this.getFeatureSet(filter, sortBy, true);
2483
    }
2484

    
2485
    @Override
2486
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2487
        return this.getFeatureSet(filter, null, true);
2488
    }
2489

    
2490
    @Override
2491
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2492
        return this.getFeatureSet(filter, sortBy, true);
2493
    }
2494

    
2495
    @Override
2496
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2497
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2498
        return this.getFeatureSet(query);
2499
    }
2500

    
2501
    @Override
2502
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2503
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2504
        return this.getFeatureSet(query);
2505
    }
2506

    
2507
    @Override
2508
    public List<Feature> getFeatures(String filter) {
2509
        return this.getFeatures(filter, null, true);
2510
    }
2511

    
2512
    @Override
2513
    public List<Feature> getFeatures(String filter, String sortBy) {
2514
        return this.getFeatures(filter, sortBy, true);
2515
    }
2516

    
2517
    @Override
2518
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc) {
2519
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2520
        return this.getFeatures(query, 0);
2521
    }
2522

    
2523
    @Override
2524
    public List<Feature> getFeatures(Expression filter) {
2525
        return this.getFeatures(filter, null, true);
2526
    }
2527

    
2528
    @Override
2529
    public List<Feature> getFeatures(Expression filter, String sortBy) {
2530
        return this.getFeatures(filter, sortBy, true);
2531
    }
2532

    
2533
    @Override
2534
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc) {
2535
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2536
        return this.getFeatures(query, 0);
2537
    }
2538

    
2539
    @Override
2540
    public List<Feature> getFeatures(FeatureQuery query) {
2541
        return this.getFeatures(query, 0);
2542
    }
2543

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

    
2562
    @Override
2563
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2564
        return this.getFeatures64(null, 0);
2565
    }
2566

    
2567
    @Override
2568
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2569
        return this.getFeatures64(filter, null, true);
2570
    }
2571

    
2572
    @Override
2573
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc) {
2574
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2575
        return this.getFeatures64(query, 0);
2576
    }
2577

    
2578
    @Override
2579
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize) {
2580
        try {
2581
            if (pageSize <= 0) {
2582
                pageSize = 100;
2583
            }
2584
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2585
            return pager;
2586
        } catch (BaseException ex) {
2587
            throw new RuntimeException("Can't create the list of features.", ex);
2588
        }
2589
    }
2590

    
2591
    @Override
2592
    public Feature first() throws DataException {
2593
        return this.findFirst((FeatureQuery) null);
2594
    }
2595

    
2596
    @Override
2597
    public Feature findFirst(String filter) throws DataException {
2598
        return this.findFirst(filter, (String) null, true);
2599
    }
2600

    
2601
    @Override
2602
    public Feature findFirst(String filter, String sortBy) throws DataException {
2603
        return this.findFirst(filter, sortBy, true);
2604
    }
2605

    
2606
    @Override
2607
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2608
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2609
        return findFirst(query);
2610
    }
2611

    
2612
    @Override
2613
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2614
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2615
        return findFirst(query);
2616
    }
2617

    
2618
    @Override
2619
    public Feature findFirst(Expression filter) throws DataException {
2620
        return this.findFirst(filter, (String) null, true);
2621
    }
2622

    
2623
    @Override
2624
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2625
        return this.findFirst(filter, sortBy, true);
2626
    }
2627

    
2628
    @Override
2629
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2630
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2631
        return findFirst(query);
2632
    }
2633

    
2634
    @Override
2635
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2636
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2637
        return findFirst(query);
2638
    }
2639

    
2640
    @Override
2641
    public Feature findFirst(FeatureQuery query) throws DataException {
2642
        if (query == null) {
2643
            query = this.createFeatureQuery();
2644
        } else {
2645
            query = query.getCopy();
2646
        }
2647
        query.setLimit(1);
2648
        final MutableObject<Feature> feature = new MutableObject<>();
2649
        try {
2650
            this.accept((Object obj) -> {
2651
                feature.setValue((Feature) obj);
2652
                throw new VisitCanceledException();
2653
            }, query);
2654
        } catch (VisitCanceledException ex) {
2655

    
2656
        } catch (DataException ex) {
2657
            throw ex;
2658
        } catch (Exception ex) {
2659
            throw new RuntimeException("", ex);
2660
        }
2661
        return feature.getValue();
2662
    }
2663

    
2664
    @Override
2665
    public void accept(Visitor visitor) throws BaseException {
2666
        this.accept(visitor, null);
2667
    }
2668

    
2669
    @Override
2670
    public void accept(Visitor visitor, DataQuery dataQuery)
2671
            throws BaseException {
2672
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2673
        try {
2674
            set.accept(visitor);
2675
        } finally {
2676
            set.dispose();
2677
        }
2678
    }
2679

    
2680
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2681
            throws DataException {
2682
        DefaultFeatureType fType
2683
                = (DefaultFeatureType) this.getFeatureType(featureQuery
2684
                        .getFeatureTypeId());
2685
        if (featureQuery.hasAttributeNames()
2686
                || featureQuery.hasConstantsAttributeNames()
2687
                || fType.hasRequiredFields()) {
2688
            if (featureQuery.hasGroupByColumns()) {
2689
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false);
2690
            } else {
2691
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2692
            }
2693
        }
2694
        return fType;
2695
    }
2696

    
2697
    @Override
2698
    public void getFeatureSet(Observer observer) throws DataException {
2699
        checkNotInAppendMode();
2700
        this.getFeatureSet(null, observer);
2701
    }
2702

    
2703
    @Override
2704
    public void getFeatureSet(FeatureQuery query, Observer observer)
2705
            throws DataException {
2706
        class LoadInBackGround implements Runnable {
2707

    
2708
            private final FeatureStore store;
2709
            private final FeatureQuery query;
2710
            private final Observer observer;
2711

    
2712
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2713
                    Observer observer) {
2714
                this.store = store;
2715
                this.query = query;
2716
                this.observer = observer;
2717
            }
2718

    
2719
            void notify(FeatureStoreNotification theNotification) {
2720
                observer.update(store, theNotification);
2721
            }
2722

    
2723
            @Override
2724
            public void run() {
2725
                FeatureSet set = null;
2726
                try {
2727
                    set = store.getFeatureSet(query);
2728
                    notify(new DefaultFeatureStoreNotification(store,
2729
                            FeatureStoreNotification.LOAD_FINISHED, set));
2730
                } catch (Exception e) {
2731
                    notify(new DefaultFeatureStoreNotification(store,
2732
                            FeatureStoreNotification.LOAD_FINISHED, e));
2733
                } finally {
2734
                    dispose(set);
2735
                }
2736
            }
2737
        }
2738

    
2739
        checkNotInAppendMode();
2740
        if (query == null) {
2741
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2742
        }
2743
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2744
        Thread thread = new Thread(task, "Load Feature Set in background");
2745
        thread.start();
2746
    }
2747

    
2748
    @Override
2749
    public Feature getFeatureByReference(FeatureReference reference)
2750
            throws DataException {
2751
        checkNotInAppendMode();
2752
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2753
        FeatureType featureType;
2754
        if (ref.getFeatureTypeId() == null) {
2755
            featureType = this.getDefaultFeatureType();
2756
        } else {
2757
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2758
        }
2759
        return this.getFeatureByReference(reference, featureType);
2760
    }
2761

    
2762
    @Override
2763
    public Feature getFeatureByReference(FeatureReference reference,
2764
            FeatureType featureType) throws DataException {
2765
        checkNotInAppendMode();
2766
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2767
        if (this.mode == MODE_FULLEDIT) {
2768
            Feature f = featureManager.get(reference, this, featureType);
2769
            if (f != null) {
2770
                return f;
2771
            }
2772
        }
2773

    
2774
        FeatureType sourceFeatureType = featureType;
2775
        if (!this.transforms.isEmpty()) {
2776
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2777
        }
2778
        // TODO comprobar que el id es de este store
2779

    
2780
        DefaultFeature feature
2781
                = new DefaultFeature(this,
2782
                        this.provider.getFeatureProviderByReference(
2783
                                (FeatureReferenceProviderServices) reference, sourceFeatureType));
2784

    
2785
        if (!this.transforms.isEmpty()) {
2786
            return this.transforms.applyTransform(feature, featureType);
2787
        }
2788
        return feature;
2789
    }
2790

    
2791
    //
2792
    // ====================================================================
2793
    // Gestion de features
2794
    //
2795
    private FeatureType fixFeatureType(DefaultFeatureType type)
2796
            throws DataException {
2797
        FeatureType original = this.getDefaultFeatureType();
2798

    
2799
        if ((type == null) || type.equals(original)) {
2800
            return original;
2801
        } else {
2802
            if (!type.isSubtypeOf(original)) {
2803
                Iterator iter = this.getFeatureTypes().iterator();
2804
                FeatureType tmpType;
2805
                boolean found = false;
2806
                while (iter.hasNext()) {
2807
                    tmpType = (FeatureType) iter.next();
2808
                    if (type.equals(tmpType)) {
2809
                        return type;
2810

    
2811
                    } else if (type.isSubtypeOf(tmpType)) {
2812
                        found = true;
2813
                        original = tmpType;
2814
                        break;
2815
                    }
2816

    
2817
                }
2818
                if (!found) {
2819
                    throw new IllegalFeatureTypeException(getName());
2820
                }
2821
            }
2822
        }
2823

    
2824
        // Checks that type has all fields of pk
2825
        // else add the missing attributes at the end.
2826
        if (!original.hasOID()) {
2827
            // Gets original pk attributes
2828
            DefaultEditableFeatureType edOriginal
2829
                    = (DefaultEditableFeatureType) original.getEditable();
2830
            FeatureAttributeDescriptor orgAttr;
2831
            Iterator edOriginalIter = edOriginal.iterator();
2832
            while (edOriginalIter.hasNext()) {
2833
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2834
                if (!orgAttr.isPrimaryKey()) {
2835
                    edOriginalIter.remove();
2836
                }
2837
            }
2838

    
2839
            // Checks if all pk attributes are in type
2840
            Iterator typeIterator;
2841
            edOriginalIter = edOriginal.iterator();
2842
            FeatureAttributeDescriptor attr;
2843
            while (edOriginalIter.hasNext()) {
2844
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2845
                typeIterator = type.iterator();
2846
                while (typeIterator.hasNext()) {
2847
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2848
                    if (attr.getName().equals(orgAttr.getName())) {
2849
                        edOriginalIter.remove();
2850
                        break;
2851
                    }
2852
                }
2853
            }
2854

    
2855
            // add missing pk attributes if any
2856
            if (edOriginal.size() > 0) {
2857
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2858
                DefaultEditableFeatureType edType
2859
                        = (DefaultEditableFeatureType) original.getEditable();
2860
                edType.clear();
2861
                edType.addAll(type);
2862
                edType.addAll(edOriginal);
2863
                if (!isEditable) {
2864
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2865
                }
2866
            }
2867

    
2868
        }
2869

    
2870
        return type;
2871
    }
2872

    
2873
    private void validateFeaturesAtFinishEditing() throws ValidateFeaturesException {
2874
        try {
2875
            checkInEditingMode();
2876
            FeatureType type = this.getDefaultFeatureTypeQuietly();
2877
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
2878

    
2879
            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS : 0;
2880
            checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
2881
            if (checks == 0) {
2882
                return;
2883
            }
2884

    
2885
            Iterator<EditableFeature> features = new ChainedIterator<>(
2886
                    featureManager.getInsertedFeatures(),
2887
                    featureManager.getUpdatedFeatures()
2888
            );
2889
            while (features.hasNext()) {
2890
                EditableFeature feature = features.next();
2891
                rules.validate(feature, checks);
2892
            }
2893
        } catch (Exception ex) {
2894
            throw new ValidateFeaturesException(this.getName(), ex);
2895
        }
2896
    }
2897

    
2898
    @Override
2899
    public FeatureType getDefaultFeatureType() throws DataException {
2900
        try {
2901

    
2902
            if (isEditing()) {
2903
                FeatureType auxFeatureType
2904
                        = featureTypeManager.getType(defaultFeatureType.getId());
2905
                if (auxFeatureType != null) {
2906
                    return avoidEditable(auxFeatureType);
2907
                }
2908
            }
2909
            FeatureType type = this.transforms.getDefaultFeatureType();
2910
            if (type != null) {
2911
                return avoidEditable(type);
2912
            }
2913

    
2914
            return avoidEditable(defaultFeatureType);
2915

    
2916
        } catch (Exception e) {
2917
            throw new GetFeatureTypeException(e, getName());
2918
        }
2919
    }
2920

    
2921
    @Override
2922
    public FeatureType getDefaultFeatureTypeQuietly() {
2923
        try {
2924
            return this.getDefaultFeatureType();
2925
        } catch (Exception ex) {
2926
            return null;
2927
        }
2928
    }
2929

    
2930
    private FeatureType avoidEditable(FeatureType ft) {
2931
        if (ft instanceof EditableFeatureType) {
2932
            return ((EditableFeatureType) ft).getNotEditableCopy();
2933
        } else {
2934
            return ft;
2935
        }
2936
    }
2937

    
2938
    @Override
2939
    public FeatureType getFeatureType(String featureTypeId)
2940
            throws DataException {
2941
        if (featureTypeId == null) {
2942
            return this.getDefaultFeatureType();
2943
        }
2944
        try {
2945
            if (isEditing()) {
2946
                FeatureType auxFeatureType
2947
                        = featureTypeManager.getType(featureTypeId);
2948
                if (auxFeatureType != null) {
2949
                    return auxFeatureType;
2950
                }
2951
            }
2952
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2953
            if (type != null) {
2954
                return type;
2955
            }
2956
            Iterator iter = this.featureTypes.iterator();
2957
            while (iter.hasNext()) {
2958
                type = (FeatureType) iter.next();
2959
                if (type.getId().equals(featureTypeId)) {
2960
                    return type;
2961
                }
2962
            }
2963
            return null;
2964
        } catch (Exception e) {
2965
            throw new GetFeatureTypeException(e, getName());
2966
        }
2967
    }
2968

    
2969
    public FeatureType getProviderDefaultFeatureType() {
2970
        return defaultFeatureType;
2971
    }
2972

    
2973
    @Override
2974
    public List getFeatureTypes() throws DataException {
2975
        try {
2976
            List types;
2977
            if (isEditing()) {
2978
                types = new ArrayList();
2979
                for (FeatureType type : featureTypes) {
2980
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2981
                    if (typeaux != null) {
2982
                        types.add(typeaux);
2983
                    } else {
2984
                        types.add(type);
2985
                    }
2986
                }
2987
                Iterator it = featureTypeManager.newsIterator();
2988
                while (it.hasNext()) {
2989
                    FeatureType type = (FeatureType) it.next();
2990
                    types.add(type);
2991
                }
2992
            } else {
2993
                types = this.transforms.getFeatureTypes();
2994
                if (types == null) {
2995
                    types = featureTypes;
2996
                }
2997
            }
2998
            return Collections.unmodifiableList(types);
2999
        } catch (Exception e) {
3000
            throw new GetFeatureTypeException(e, getName());
3001
        }
3002
    }
3003

    
3004
    public List getProviderFeatureTypes() throws DataException {
3005
        return Collections.unmodifiableList(this.featureTypes);
3006
    }
3007

    
3008
    @Override
3009
    public Feature createFeature(FeatureProvider data) throws DataException {
3010
        DefaultFeature feature = new DefaultFeature(this, data);
3011
        return feature;
3012
    }
3013

    
3014
    public Feature createFeature(FeatureProvider data, FeatureType type)
3015
            throws DataException {
3016
        // FIXME: falta por implementar
3017
        // Comprobar si es un subtipo del feature de data
3018
        // y construir un feature usando el subtipo.
3019
        // Probablemente requiera generar una copia del data.
3020
        throw new NotYetImplemented();
3021
    }
3022

    
3023
    @Override
3024
    public EditableFeature createNewFeature(FeatureType type,
3025
            Feature defaultValues) throws DataException {
3026
        try {
3027
            FeatureProvider data = createNewFeatureProvider(type);
3028
            DefaultEditableFeature feature
3029
                    = new DefaultEditableFeature(this, data);
3030
            feature.initializeValues(defaultValues);
3031
            data.setNew(true);
3032

    
3033
            return feature;
3034
        } catch (Exception e) {
3035
            throw new CreateFeatureException(e, getName());
3036
        }
3037
    }
3038

    
3039
    private FeatureProvider createNewFeatureProvider(FeatureType type)
3040
            throws DataException {
3041
        type = this.fixFeatureType((DefaultFeatureType) type);
3042
        FeatureProvider data = this.provider.createFeatureProvider(type);
3043
        data.setNew(true);
3044
        if (type.hasOID() && (data.getOID() == null)) {
3045
            data.setOID(this.provider.createNewOID());
3046
        } else {
3047
            data.setOID(this.getTemporalOID());
3048
        }
3049
        return data;
3050

    
3051
    }
3052

    
3053
    @Override
3054
    public EditableFeature createNewFeature(FeatureType type,
3055
            boolean defaultValues) throws DataException {
3056
        try {
3057
            FeatureProvider data = createNewFeatureProvider(type);
3058
            DefaultEditableFeature feature
3059
                    = new DefaultEditableFeature(this, data);
3060
            if (defaultValues) {
3061
                feature.initializeValues();
3062
            }
3063
            return feature;
3064
        } catch (Exception e) {
3065
            throw new CreateFeatureException(e, getName());
3066
        }
3067
    }
3068

    
3069
    @Override
3070
    public EditableFeature createNewFeature(boolean defaultValues)
3071
            throws DataException {
3072
        return this.createNewFeature(this.getDefaultFeatureType(),
3073
                defaultValues);
3074
    }
3075

    
3076
    @Override
3077
    public EditableFeature createNewFeature() throws DataException {
3078
        return this.createNewFeature(this.getDefaultFeatureType(), true);
3079
    }
3080

    
3081
    @Override
3082
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
3083
        FeatureType ft = this.getDefaultFeatureType();
3084
        EditableFeature f = this.createNewFeature(ft, false);
3085
        f.copyFrom(defaultValues);
3086
        return f;
3087
    }
3088

    
3089
    @Override
3090
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
3091
        FeatureType ft = this.getDefaultFeatureType();
3092
        EditableFeature f = this.createNewFeature(ft, false);
3093
        f.copyFrom(defaultValues);
3094
        return f;
3095
    }
3096

    
3097
    @Override
3098
    public EditableFeatureType createFeatureType() {
3099
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
3100
        return ftype;
3101
    }
3102

    
3103
    @Override
3104
    public EditableFeatureType createFeatureType(String id) {
3105
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
3106
        return ftype;
3107
    }
3108

    
3109
    //
3110
    // ====================================================================
3111
    // Index related methods
3112
    //
3113
    @Override
3114
    public FeatureIndexes getIndexes() {
3115
        return this.indexes;
3116
    }
3117

    
3118
    @Override
3119
    public FeatureIndex createIndex(FeatureType featureType,
3120
            String attributeName, String indexName) throws DataException {
3121
        return createIndex(null, featureType, attributeName, indexName);
3122
    }
3123

    
3124
    @Override
3125
    public FeatureIndex createIndex(String indexTypeName,
3126
            FeatureType featureType, String attributeName, String indexName)
3127
            throws DataException {
3128

    
3129
        return createIndex(indexTypeName, featureType, attributeName,
3130
                indexName, false, null);
3131
    }
3132

    
3133
    @Override
3134
    public FeatureIndex createIndex(FeatureType featureType,
3135
            String attributeName, String indexName, Observer observer)
3136
            throws DataException {
3137
        return createIndex(null, featureType, attributeName, indexName,
3138
                observer);
3139
    }
3140

    
3141
    @Override
3142
    public FeatureIndex createIndex(String indexTypeName,
3143
            FeatureType featureType, String attributeName, String indexName,
3144
            final Observer observer) throws DataException {
3145

    
3146
        return createIndex(indexTypeName, featureType, attributeName,
3147
                indexName, true, observer);
3148
    }
3149

    
3150
    private FeatureIndex createIndex(String indexTypeName,
3151
            FeatureType featureType, String attributeName, String indexName,
3152
            boolean background, final Observer observer) throws DataException {
3153

    
3154
        checkNotInAppendMode();
3155
        FeatureIndexProviderServices index;
3156
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
3157
                featureType, indexName,
3158
                featureType.getAttributeDescriptor(attributeName));
3159

    
3160
        try {
3161
            index.fill(background, observer);
3162
        } catch (FeatureIndexException e) {
3163
            throw new InitializeException(index.getName(), e);
3164
        }
3165

    
3166
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
3167
        return index;
3168
    }
3169

    
3170
    //
3171
    // ====================================================================
3172
    // Transforms related methods
3173
    //
3174
    @Override
3175
    public FeatureStoreTransforms getTransforms() {
3176
        return this.transforms;
3177
    }
3178

    
3179
    @Override
3180
    public FeatureQuery createFeatureQuery() {
3181
        return new DefaultFeatureQuery(this.getName());
3182
    }
3183

    
3184
    @Override
3185
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
3186
        FeatureQuery query = null;
3187
        if ( !ExpressionUtils.isPhraseEmpty(filter) ) {
3188
            query = this.createFeatureQuery();
3189
            query.setFilter(filter);
3190
        }
3191
        if (!StringUtils.isBlank(sortBy)) {
3192
            if (query == null) {
3193
                query = this.createFeatureQuery();
3194
            }
3195
            if (StringUtils.containsAny(sortBy, "(", ")")) {
3196
                throw new IllegalArgumentException("Incorrect sortBy expression");
3197
            }
3198
            String[] attrnames;
3199
            if (sortBy.contains(",")) {
3200
                attrnames = StringUtils.split(sortBy, ",");
3201
            } else {
3202
                attrnames = new String[]{sortBy};
3203
            }
3204
            for (String attrname : attrnames) {
3205
                attrname = attrname.trim();
3206
                if (attrname.startsWith("-")) {
3207
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(1).trim(),'"'), false);
3208
                } else if (attrname.endsWith("-")) {
3209
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(0, sortBy.length() - 1).trim(),'"'), false);
3210
                } else if (attrname.startsWith("+")) {
3211
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(1).trim(),'"'), true);
3212
                } else if (attrname.endsWith("-")) {
3213
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(0, sortBy.length() - 1).trim(),'"'), true);
3214
                } else {
3215
                    query.getOrder().add(StringUtils.unwrap(attrname,'"'), asc);
3216
                }
3217
            }
3218
        }
3219
        if (query != null) {
3220
            query.retrievesAllAttributes();
3221
        }
3222
        return query;
3223
    }
3224

    
3225
    @Override
3226
    public FeatureQuery createFeatureQuery(String filter) {
3227
        return this.createFeatureQuery( 
3228
                ExpressionUtils.createExpression(filter),
3229
                (String) null,
3230
                true
3231
        );
3232
    }
3233

    
3234
    @Override
3235
    public FeatureQuery createFeatureQuery(Expression filter) {
3236
        return this.createFeatureQuery(
3237
                filter,
3238
                (String) null,
3239
                true
3240
        );
3241
    }
3242

    
3243
    @Override
3244
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
3245
        if (StringUtils.isBlank(filter)) {
3246
            return this.createFeatureQuery(
3247
                    (Expression) null,
3248
                    sortBy,
3249
                    asc
3250
            );
3251
        } else {
3252
            return this.createFeatureQuery(
3253
                    ExpressionUtils.createExpression(filter),
3254
                    sortBy,
3255
                    asc
3256
            );
3257
        }
3258
    }
3259

    
3260
    @Override
3261
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
3262
        FeatureQuery query = null;
3263
        if (filter != null) {
3264
            query = this.createFeatureQuery();
3265
            query.setFilter(filter);
3266
        }
3267
        if (sortBy != null) {
3268
            if (query == null) {
3269
                query = this.createFeatureQuery();
3270
            }
3271
            query.getOrder().add(sortBy, asc);
3272
        }
3273

    
3274
        if (query != null) {
3275
            query.retrievesAllAttributes();
3276
        }
3277
        return query;
3278
    }
3279

    
3280
    @Override
3281
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3282
        if (StringUtils.isBlank(filter)) {
3283
            return this.createFeatureQuery(
3284
                    (Expression) null,
3285
                    sortBy,
3286
                    asc
3287
            );
3288
        } else {
3289
            return this.createFeatureQuery(
3290
                    ExpressionUtils.createExpression(filter),
3291
                    sortBy,
3292
                    asc
3293
            );
3294
        }
3295
    }
3296

    
3297
    @Override
3298
    public DataQuery createQuery() {
3299
        return createFeatureQuery();
3300
    }
3301

    
3302
    //
3303
    // ====================================================================
3304
    // UndoRedo related methods
3305
    //
3306
    @Override
3307
    public boolean canRedo() {
3308
        return commands.canRedo();
3309
    }
3310

    
3311
    @Override
3312
    public boolean canUndo() {
3313
        return commands.canUndo();
3314
    }
3315

    
3316
    @Override
3317
    public void redo(int num) throws RedoException {
3318
        for (int i = 0; i < num; i++) {
3319
            redo();
3320
        }
3321
    }
3322

    
3323
    @Override
3324
    public void undo(int num) throws UndoException {
3325
        for (int i = 0; i < num; i++) {
3326
            undo();
3327
        }
3328
    }
3329

    
3330
    //
3331
    // ====================================================================
3332
    // Metadata related methods
3333
    //
3334
    @Override
3335
    public Object getMetadataID() {
3336
        return this.provider.getSourceId();
3337
    }
3338

    
3339
    @Override
3340
    public void delegate(DynObject dynObject) {
3341
        this.metadata.delegate(dynObject);
3342
    }
3343

    
3344
    @Override
3345
    public DynClass getDynClass() {
3346
        return this.metadata.getDynClass();
3347
    }
3348

    
3349
    @Override
3350
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3351
        try {
3352
            if (this.transforms.hasDynValue(name)) {
3353
                return this.transforms.getDynValue(name);
3354
            }
3355
            if (this.metadata.hasDynValue(name)) {
3356
                return this.metadata.getDynValue(name);
3357
            }
3358
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3359
                return this.provider.getProviderName();
3360
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3361
                return this.provider.getSourceId();
3362
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3363
                try {
3364
                    return this.getDefaultFeatureType();
3365
                } catch (DataException e) {
3366
                    return null;
3367
                }
3368
            }
3369
            return this.metadata.getDynValue(name);
3370
        } catch (Exception ex) {
3371
            LOGGER.debug("Can't retrieve the value of '" + name + "' in store '" + this.getName() + "'.", ex);
3372
            return null;
3373
        }
3374
    }
3375

    
3376
    @Override
3377
    public boolean hasDynValue(String name) {
3378
        if (this.transforms.hasDynValue(name)) {
3379
            return true;
3380
        }
3381
        if (this.provider.hasDynValue(name)) {
3382
            return true;
3383
        }
3384
        if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3385
            return true;
3386
        } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3387
            return true;
3388
        } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3389
            return true;
3390
        }
3391
        return this.metadata.hasDynValue(name);
3392
    }
3393

    
3394
    @Override
3395
    public boolean hasDynMethod(String name) {
3396
        return ((DynObject_v2) this.metadata).hasDynMethod(name);
3397
    }
3398

    
3399
    @Override
3400
    public void implement(DynClass dynClass) {
3401
        this.metadata.implement(dynClass);
3402
    }
3403

    
3404
    @Override
3405
    public Object invokeDynMethod(String name, Object[] args)
3406
            throws DynMethodException {
3407
        return this.metadata.invokeDynMethod(this, name, args);
3408
    }
3409

    
3410
    @Override
3411
    public Object invokeDynMethod(int code, Object[] args)
3412
            throws DynMethodException {
3413
        return this.metadata.invokeDynMethod(this, code, args);
3414
    }
3415

    
3416
    @Override
3417
    public void setDynValue(String name, Object value)
3418
            throws DynFieldNotFoundException {
3419
        if (this.transforms.hasDynValue(name)) {
3420
            this.transforms.setDynValue(name, value);
3421
            return;
3422
        }
3423
        this.metadata.setDynValue(name, value);
3424

    
3425
    }
3426

    
3427
    /*
3428
     * (non-Javadoc)
3429
     *
3430
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3431
     */
3432
    @Override
3433
    public Set getMetadataChildren() {
3434
        return this.metadataChildren;
3435
    }
3436

    
3437
    /*
3438
     * (non-Javadoc)
3439
     *
3440
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3441
     */
3442
    @Override
3443
    public String getMetadataName() {
3444
        return this.provider.getProviderName();
3445
    }
3446

    
3447
    public FeatureTypeManager getFeatureTypeManager() {
3448
        return this.featureTypeManager;
3449
    }
3450

    
3451
    @Override
3452
    public long getFeatureCount() throws DataException {
3453
        if (featureCount == null) {
3454
            featureCount = this.provider.getFeatureCount();
3455
        }
3456
        if (this.isEditing()) {
3457
            if (this.isAppending()) {
3458
                try {
3459
                    throw new IllegalStateException();
3460
                } catch (IllegalStateException e) {
3461
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND", e);
3462
                }
3463
                return -1;
3464
            } else {
3465
                return featureCount
3466
                        + this.featureManager.getDeltaSize();
3467
            }
3468
        }
3469
        return featureCount;
3470
    }
3471

    
3472
    private Long getTemporalOID() {
3473
        return this.temporalOid++;
3474
    }
3475

    
3476
    @Override
3477
    public FeatureType getProviderFeatureType(String featureTypeId) {
3478
        if (featureTypeId == null) {
3479
            return this.defaultFeatureType;
3480
        }
3481
        FeatureType type;
3482
        Iterator iter = this.featureTypes.iterator();
3483
        while (iter.hasNext()) {
3484
            type = (FeatureType) iter.next();
3485
            if (type.getId().equals(featureTypeId)) {
3486
                return type;
3487
            }
3488
        }
3489
        return null;
3490
    }
3491

    
3492
    @Override
3493
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3494
        return ((DefaultFeature) feature).getData();
3495
    }
3496

    
3497
    @Override
3498
    public DataStore getStore() {
3499
        return this;
3500
    }
3501

    
3502
    @Override
3503
    public FeatureStore getFeatureStore() {
3504
        return this;
3505
    }
3506

    
3507
    @Override
3508
    public void createCache(String name, DynObject parameters)
3509
            throws DataException {
3510
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3511
        if (cache == null) {
3512
            throw new CreateException("FeaureCacheProvider", null);
3513
        }
3514
        cache.apply(this, provider);
3515
        provider = cache;
3516

    
3517
        featureCount = null;
3518
    }
3519

    
3520
    @Override
3521
    public FeatureCache getCache() {
3522
        return cache;
3523
    }
3524

    
3525
    @Override
3526
    public void clear() {
3527
        if (metadata != null) {
3528
            metadata.clear();
3529
        }
3530
    }
3531

    
3532
    @Override
3533
    public String getName() {
3534
        if (this.provider != null) {
3535
            return this.provider.getName();
3536
        }
3537
        if (this.parameters instanceof HasAFile) {
3538
            return FilenameUtils.getName(((HasAFile) this.parameters).getFile().getName());
3539
        }
3540
        return "unknow";
3541
    }
3542

    
3543
    @Override
3544
    public String getFullName() {
3545
        try {
3546
            String fullname = null;
3547
            if (this.provider != null) {
3548
                fullname = this.provider.getFullName();
3549
            }
3550
            if ( StringUtils.isBlank(fullname) && this.parameters instanceof HasAFile) {
3551
                fullname = (((HasAFile) this.parameters).getFile().getAbsolutePath());
3552
            }
3553
            if(StringUtils.isBlank(fullNameForTraces) ) {
3554
                fullNameForTraces = fullname;
3555
            }
3556
            return fullname;
3557
        } catch (Throwable th) {
3558
            return null;
3559
        }
3560
    }
3561
    
3562
    protected String getFullNameForTraces() {
3563
        if(StringUtils.isBlank(fullNameForTraces) ) {
3564
            return this.getFullName();
3565
        }
3566
        return fullNameForTraces;
3567
    }
3568

    
3569
    @Override
3570
    public String getProviderName() {
3571
        if (this.provider != null) {
3572
            return this.provider.getProviderName();
3573
        }
3574
        if (this.parameters != null) {
3575
            return this.parameters.getDataStoreName();
3576
        }
3577
        return null;
3578

    
3579
    }
3580

    
3581
    @Override
3582
    public boolean isKnownEnvelope() {
3583
        return this.provider.isKnownEnvelope();
3584
    }
3585

    
3586
    @Override
3587
    public boolean hasRetrievedFeaturesLimit() {
3588
        return this.provider.hasRetrievedFeaturesLimit();
3589
    }
3590

    
3591
    @Override
3592
    public int getRetrievedFeaturesLimit() {
3593
        return this.provider.getRetrievedFeaturesLimit();
3594
    }
3595

    
3596
    @Override
3597
    public Interval getInterval() {
3598
        if (this.timeSupport != null) {
3599
            return this.timeSupport.getInterval();
3600
        }
3601
        try {
3602
            FeatureType type = this.getDefaultFeatureType();
3603
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3604
            if (attr != null) {
3605
                Interval interval = attr.getInterval();
3606
                if (interval != null) {
3607
                    return interval;
3608
                }
3609
            }
3610
        } catch (DataException ex) {
3611
        }
3612
        return this.provider.getInterval();
3613
    }
3614

    
3615
    @Override
3616
    public Collection getTimes() {
3617
        if (this.timeSupport != null) {
3618
            return this.timeSupport.getTimes();
3619
        }
3620
        return this.provider.getTimes();
3621
    }
3622

    
3623
    @Override
3624
    public Collection getTimes(Interval interval) {
3625
        if (this.timeSupport != null) {
3626
            return this.timeSupport.getTimes(interval);
3627
        }
3628
        return this.provider.getTimes(interval);
3629
    }
3630

    
3631
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3632
        if (this.isEditing()) {
3633
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' while store is editing.");
3634
        }
3635
        if (!this.transforms.isEmpty()) {
3636
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' if has transforms.");
3637
        }
3638
        FeatureType ft = this.defaultFeatureType;
3639
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3640
        if (attr == null) {
3641
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "', this attribute don't exists.");
3642
        }
3643
        EditableFeatureType eft = ft.getEditable();
3644
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3645
        if (attr != null) {
3646
            if (!(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport)) {
3647
                throw new RuntimeException("Can't add time support, attribute '" + timeSupport.getAttributeName() + "'already exists.");
3648
            }
3649
            eft.remove(attr.getName());
3650
        }
3651
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3652
                timeSupport.getAttributeName(),
3653
                timeSupport.getDataType()
3654
        );
3655
        attrTime.setIsTime(true);
3656
        attrTime.setFeatureAttributeEmulator(timeSupport);
3657
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3658
        this.defaultFeatureType = eft.getNotEditableCopy();
3659

    
3660
        this.timeSupport = timeSupport;
3661
    }
3662

    
3663
    @Override
3664
    @SuppressWarnings("CloneDoesntCallSuperClone")
3665
    public Object clone() throws CloneNotSupportedException {
3666

    
3667
        DataStoreParameters dsp = getParameters();
3668

    
3669
        DefaultFeatureStore cloned_store = null;
3670

    
3671
        try {
3672
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3673
                    openStore(this.getProviderName(), dsp);
3674
            if (transforms != null) {
3675
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3676
                cloned_store.transforms.setStoreForClone(cloned_store);
3677
            }
3678
        } catch (Exception e) {
3679
            throw new CloneException(e);
3680
        }
3681
        return cloned_store;
3682

    
3683
    }
3684

    
3685
    @Override
3686
    public Feature getFeature(DynObject dynobject) {
3687
        if (dynobject instanceof DynObjectFeatureFacade) {
3688
            Feature f = ((DynObjectFeatureFacade) dynobject).getFeature();
3689
            return f;
3690
        }
3691
        return null;
3692
    }
3693

    
3694
    @Override
3695
    public Iterator iterator() {
3696
        FeatureSet fset = null;
3697
        try {
3698
            fset = this.getFeatureSet();
3699
            return fset.fastIterator();
3700
        } catch (DataException ex) {
3701
            throw new RuntimeException(ex);
3702
        } finally {
3703
            DisposeUtils.disposeQuietly(fset);
3704
        }
3705
    }
3706

    
3707
    @Override
3708
    public long size64() {
3709
        FeatureSet fset = null;
3710
        try {
3711
            fset = this.getFeatureSet();
3712
            return fset.getSize();
3713
        } catch (DataException ex) {
3714
            throw new RuntimeException(ex);
3715
        } finally {
3716
            DisposeUtils.disposeQuietly(fset);
3717
        }
3718
    }
3719

    
3720
    @Override
3721
    public ExpressionBuilder createExpressionBuilder() {
3722
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3723
        return builder;
3724
    }
3725

    
3726
    @Override
3727
    public ExpressionBuilder createExpression() {
3728
        return createExpressionBuilder();
3729
    }
3730

    
3731
    public FeatureSet features() throws DataException {
3732
        // This is to avoid jython to create a property with this name
3733
        // to access method getFeatures.
3734
        return this.getFeatureSet();
3735
    }
3736

    
3737
    @Override
3738
    public DataStoreProviderFactory getProviderFactory() {
3739
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3740
        return factory;
3741
    }
3742

    
3743
    @Override
3744
    public void useCache(String providerName, DynObject parameters) throws DataException {
3745
        throw new UnsupportedOperationException();
3746
    }
3747

    
3748
    @Override
3749
    public boolean isBroken() {
3750
        return this.state.isBroken();
3751
    }
3752

    
3753
    @Override
3754
    public Throwable getBreakingsCause() {
3755
        return this.state.getBreakingsCause();
3756
    }
3757

    
3758
    @Override
3759
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3760
        FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3761
        if (!factory.supportNumericOID()) {
3762
            return null;
3763
        }
3764
        SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3765
        return wrappedIndex;
3766
    }
3767

    
3768
    @Override
3769
    public FeatureReference getFeatureReference(String code) {
3770
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3771
        return featureReference;
3772
    }
3773

    
3774
    @Override
3775
    public long getPendingChangesCount() {
3776
        if (this.featureManager == null) {
3777
            return 0;
3778
        }
3779
        return this.featureManager.getPendingChangesCount();
3780
    }
3781

    
3782
    private ResourcesStorage resourcesStorage;
3783

    
3784
    @Override
3785
    public ResourcesStorage getResourcesStorage() {
3786
        if (this.resourcesStorage != null) {
3787
            DisposeUtils.bind(this.resourcesStorage);
3788
            return this.resourcesStorage;
3789
        }
3790
        ResourcesStorage theResourcesStorage;
3791
        try {
3792
            theResourcesStorage = this.provider.getResourcesStorage();
3793
            if (theResourcesStorage != null) {
3794
                this.resourcesStorage = theResourcesStorage;
3795
                DisposeUtils.bind(this.resourcesStorage);
3796
                return theResourcesStorage;
3797
            }
3798
        } catch (Throwable th) {
3799

    
3800
        }
3801
        try {
3802
            DataServerExplorer explorer = this.getExplorer();
3803
            if (explorer == null) {
3804
                return null;
3805
            }
3806
            theResourcesStorage = explorer.getResourcesStorage(this);
3807
            explorer.dispose();
3808
            this.resourcesStorage = theResourcesStorage;
3809
            DisposeUtils.bind(this.resourcesStorage);
3810
            return theResourcesStorage;
3811
        } catch (Exception ex) {
3812
            LOGGER.trace("Can't create resources storage", ex);
3813
            return null;
3814
        }
3815
    }
3816

    
3817
    @Override
3818
    public StoresRepository getStoresRepository() {
3819
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3820
        StoresRepository localRepository = this.provider.getStoresRepository();
3821
        if (localRepository == null) {
3822
            return mainRepository;
3823
        }
3824
        StoresRepository repository = new BaseStoresRepository(this.getName());
3825
        repository.addRepository(localRepository);
3826
        repository.addRepository(mainRepository);
3827
        return repository;
3828
    }
3829

    
3830
    @Override
3831
    public Feature getSampleFeature() {
3832
        if( sampleFeatureCache==null )  {
3833
            this.sampleFeatureCache = new CachedValue<Feature>(sample_feature_cache_timeout_ms) {
3834
                @Override
3835
                protected void reload() {
3836
                    Feature sampleFeature;
3837
                    long t1 = System.currentTimeMillis();
3838
                    try {                        
3839
                        FeatureSelection theSelection = getFeatureSelection();
3840
                        if (theSelection != null && !theSelection.isEmpty()) {
3841
                            sampleFeature = theSelection.first();
3842
                        } else {
3843
                            sampleFeature = first();
3844
                        }
3845
                        if (sampleFeature == null) {
3846
                            sampleFeature = createNewFeature();
3847
                        }
3848
                    } catch (Exception ex) {
3849
                        sampleFeature = null;
3850
                    }
3851
                    long t2 = System.currentTimeMillis();
3852
                    if( (t2 - t1)>5000 ) {
3853
                        // Mas de 5 seg es muy costoso, subimos mucho el tiempo de cache.
3854
                        this.setExpireTime(((60*60)*2)*1000); // 2h
3855
                    }
3856
                    this.setValue(sampleFeature);
3857
                }
3858
            };
3859
        }
3860
        return this.sampleFeatureCache.get();
3861
    }
3862

    
3863
    @Override
3864
    public boolean supportReferences() {
3865
        try {
3866
            return this.getDefaultFeatureType().supportReferences();
3867
        } catch (Exception ex) {
3868
            return false;
3869
        }
3870
    }
3871

    
3872
    private Boolean temporary = null;
3873
    
3874
    @Override
3875
    public boolean isTemporary() {
3876
        if(temporary != null) {
3877
            return this.temporary;
3878
        }
3879
        if (this.provider == null) {
3880
            return true;
3881
        }
3882
        return this.provider.isTemporary();
3883
    }
3884
    
3885
    @Override
3886
    public void setTemporary(Boolean temporary){
3887
        this.temporary = temporary;
3888
    }
3889

    
3890
    public FeatureType getOriginalFeatureType(FeatureType featureType) {
3891
        // FIXME this don't work for Store.fType.size() > 1
3892
        FeatureTypeManager manager = this.featureTypeManager;
3893
        if (manager == null) {
3894
            return null;
3895
        }
3896
        FeatureType originalFeatureType = manager.getOriginalFeatureType();
3897
        if (originalFeatureType == null) {
3898
            return null;
3899
        }
3900
        return originalFeatureType.getCopy();
3901
    }
3902

    
3903
    @Override
3904
    public Object getProperty(String name) {
3905
        if (this.propertiesSupportHelper == null) {
3906
            return null;
3907
        }
3908
        return this.propertiesSupportHelper.getProperty(name);
3909
    }
3910

    
3911
    @Override
3912
    public void setProperty(String name, Object value) {
3913
        if (this.propertiesSupportHelper == null) {
3914
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3915
        }
3916
        this.propertiesSupportHelper.setProperty(name, value);
3917
    }
3918

    
3919
    @Override
3920
    public Map<String, Object> getProperties() {
3921
        if (this.propertiesSupportHelper == null) {
3922
            return Collections.EMPTY_MAP;
3923
        }
3924
        return this.propertiesSupportHelper.getProperties();
3925
    }
3926

    
3927
    @Override
3928
    public Feature getOriginalFeature(FeatureReference id) {
3929
        if (this.featureManager == null) {
3930
            return null;
3931
        }
3932
        return featureManager.getOriginal(id);
3933
    }
3934

    
3935
    @Override
3936
    public Feature getOriginalFeature(Feature feature) {
3937
        if (feature == null) {
3938
            return null;
3939
        }
3940
        return getOriginalFeature(feature.getReference());
3941
    }
3942

    
3943
    @Override
3944
    public boolean isFeatureModified(FeatureReference id) {
3945
        if (this.featureManager == null) {
3946
            return false;
3947
        }
3948
        return featureManager.isFeatureModified(id);
3949
    }
3950

    
3951
    @Override
3952
    public boolean isFeatureModified(Feature feature) {
3953
        if (feature == null) {
3954
            return false;
3955
        }
3956
        return isFeatureModified(feature.getReference());
3957
    }
3958

    
3959
    @Override
3960
    public void setTransaction(DataTransaction transaction) {
3961
        if( this.transaction!=null ) {
3962
            this.transaction.deleteObserver(transactionObserver);
3963
        }
3964
        this.transaction = transaction;
3965
        if (transaction == null || transaction instanceof DataTransactionServices) {
3966
            this.provider.setTransaction((DataTransactionServices) transaction);
3967
        }
3968
        if( transaction!=null ) {
3969
            transaction.addObserver(transactionObserver);
3970
        }
3971
    }
3972

    
3973
    @Override
3974
    public DataTransaction getTransaction() {
3975
        return transaction;
3976
    }
3977

    
3978
    @Override
3979
    public String toString() {
3980
        try {
3981
            return String.format("%s %x %s", this.getClass().getSimpleName(), this.hashCode(), this.getFullName());
3982
        } catch (Exception e) {
3983
            return super.toString();
3984
        }
3985
    }
3986

    
3987
    public String createUniqueID() {
3988
        UUID x = UUID.randomUUID();
3989
        String s = x.toString();
3990
        return s;
3991
    }
3992

    
3993
    @Override
3994
    public List<FeatureReference> getEditedFeatures() {
3995
        if( this.featureManager == null ) {
3996
            return Collections.EMPTY_LIST;
3997
        }
3998
        List<FeatureReference> references = this.featureManager.getAddedAndUpdatedFeatures();
3999
        if( references==null ) {
4000
            return Collections.EMPTY_LIST;
4001
        }
4002
        return references;
4003
    }
4004
    
4005
    public List<FeatureReference> getEditedFeaturesNotValidated() {
4006

    
4007
        try {
4008
            if (this.featureManager == null) {
4009
                return Collections.EMPTY_LIST;
4010
            }
4011
            
4012
            FeatureType type = this.getDefaultFeatureTypeQuietly();
4013
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
4014
            
4015
//            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS | CHECK_BASIC : 0;
4016
            int checks = CHECK_REQUIREDS | CHECK_BASIC;
4017
            if(type.isCheckFeaturesAtFinishEditing()){
4018
                checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
4019
            }
4020
            if (checks == 0) {
4021
                return Collections.EMPTY_LIST;
4022
            }
4023
            List<FeatureReference> references = this.featureManager
4024
                    .getAddedAndUpdatedFeaturesNotValidated(rules, checks);
4025
            if (references == null) {
4026
                return Collections.EMPTY_LIST;
4027
            }
4028
            return references;
4029
        } catch (DataException ex) {
4030
            return null;
4031
        }
4032

    
4033
    }
4034

    
4035
    @Override
4036
    public Iterator<Feature> getFeaturesIterator(Iterator<FeatureReference> references) {
4037
        return new FeatureReferenceIteratorToFeatureIterator(this, references);
4038
    }
4039

    
4040
    @Override
4041
    public Iterable<Feature> getFeaturesIterable(Iterator<FeatureReference> references) {
4042
        return () -> new FeatureReferenceIteratorToFeatureIterator(this, references);
4043
    }
4044

    
4045
    @Override
4046
    public boolean isFeatureSelectionAvailable() {
4047
        try {
4048
            FeatureType type = this.getDefaultFeatureType();
4049
            return type.supportReferences();
4050
        } catch (DataException ex) {
4051
            return false;
4052
        }
4053
    }
4054
    
4055
    public boolean canBeEdited() {
4056
        return this.transforms.isEmpty();
4057
    }
4058
}