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

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

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

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

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

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

    
214
    private FeatureCommandsStack commands;
215

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

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

    
226
    private int mode = MODE_QUERY;
227
    private int submode = SUBMODE_NONE;
228
    
229
    private int lastMode = MODE_QUERY;
230
    
231
    private long versionOfUpdate = 0;
232
    private boolean hasStrongChanges = true;
233

    
234
    private DefaultDataManager dataManager = null;
235

    
236
    private FeatureStoreProvider provider = null;
237

    
238
    private DefaultFeatureIndexes indexes;
239

    
240
    private DefaultFeatureStoreTransforms transforms;
241

    
242
    /*friend*/ DelegatedDynObject metadata;
243

    
244
    private Set metadataChildren;
245

    
246
    private Long featureCount = null;
247

    
248
    private long temporalOid = 0;
249

    
250
    private FeatureCacheProvider cache;
251

    
252
    private final StateInformation state;
253

    
254
    private FeatureStoreTimeSupport timeSupport;
255

    
256
    private PropertiesSupportHelper propertiesSupportHelper;
257

    
258
    private final SupportTransactionsHelper transactionHelper;
259

    
260
    private String editingSessionCode;
261
    private String lastEditingSessionCode;
262
    
263
    private CachedValue<Feature> sampleFeatureCache;
264
    
265
    private final Observer transactionObserver;
266
    private String fullNameForTraces;
267

    
268
    private class StateInformation extends HashMap<Object, Object> {
269

    
270
        private static final long serialVersionUID = 4109026189635185666L;
271

    
272
        private boolean broken;
273
        private Throwable breakingsCause;
274

    
275
        @SuppressWarnings("OverridableMethodCallInConstructor")
276
        public StateInformation() {
277
            this.clear();
278
        }
279

    
280
        @Override
281
        public void clear() {
282
            this.broken = false;
283
            this.breakingsCause = null;
284
            super.clear();
285
        }
286

    
287
        public boolean isBroken() {
288
            return this.broken;
289
        }
290

    
291
        public void broken() {
292
            this.broken = true;
293
        }
294

    
295
        public Throwable getBreakingsCause() {
296
            return this.breakingsCause;
297
        }
298

    
299
        public void setBreakingsCause(Throwable cause) {
300
            if (this.breakingsCause == null) {
301
                this.breakingsCause = cause;
302
            }
303
            this.broken = true;
304
        }
305
    }
306

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

    
329
    @Override
330
    protected DataManager getDataManager() {
331
        return this.dataManager;
332
    }
333

    
334
    @Override
335
    public void intialize(DataManager dataManager,
336
            DataStoreParameters parameters) throws InitializeException {
337

    
338
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
339

    
340
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
341
                FeatureStore.METADATA_DEFINITION_NAME,
342
                MetadataManager.METADATA_NAMESPACE
343
        );
344

    
345
        this.dataManager = (DefaultDataManager) dataManager;
346

    
347
        this.parameters = parameters;
348
        this.transforms = new DefaultFeatureStoreTransforms(this);
349
        try {
350
            indexes = new DefaultFeatureIndexes(this);
351
        } catch (DataException e) {
352
            throw new InitializeException(e);
353
        }
354

    
355
    }
356

    
357
    @Override
358
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
359
        this.provider = (FeatureStoreProvider) provider;
360
        this.delegate((DynObject) provider);
361
        this.metadataChildren = new HashSet();
362
        this.metadataChildren.add(provider);
363
        if (!this.ignoreDALResource) {
364
            loadDALFile();
365
            // Este metodo en el proveedor da prioridad
366
            // a los parametros frente a lo que se ha leido en el fichero dal
367
            this.provider.fixFeatureTypeFromParameters();
368
            try {
369
                if (defaultFeatureType != null) {
370
                    FeatureAttributeDescriptor attrGeom = defaultFeatureType.getDefaultGeometryAttribute();
371
                    if (attrGeom != null) {
372
                        DefaultFeatureAttributeDescriptor gattr = (DefaultFeatureAttributeDescriptor) attrGeom;
373
                        IProjection srs = (IProjection) this.getDynValue(METADATA_CRS);
374
                        if (srs != null && srs != gattr.getSRS()) {
375
                            gattr.setSRSForced(srs);
376
                        }
377
                    }
378
                }
379
            } catch (Throwable th) {
380
                LOGGER.warn("Can't patch DAL file", th);
381
            }
382
        }
383
    }
384

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

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

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

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

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

    
417
    public FeatureManager getFeatureManager() {
418
        return this.featureManager;
419
    }
420

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

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

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

    
461
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
462
    }
463

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

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

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

    
515
        this.featureManager = null;
516
        this.spatialManager = null;
517

    
518
        this.parameters = null;
519
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
520
        if (delegateObservable != null) {
521
            this.delegateObservable.deleteObservers();
522
            this.delegateObservable = null;
523
        }
524
        DisposeUtils.disposeQuietly(this.resourcesStorage);
525
        DataTransaction transaction = this.getTransaction();
526
        if( transaction!=null ) {
527
            transaction.remove(this);
528
            this.setTransaction(null);
529
        }
530
    }
531

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

    
541
    @Override
542
    public boolean canWriteGeometry(int geometryType) throws DataException {
543
        return this.provider.canWriteGeometry(geometryType, 0);
544
    }
545

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

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

    
635
    /**
636
     * @throws org.gvsig.fmap.dal.exception.DataException
637
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
638
     */
639
    @Override
640
    public IProjection getSRSDefaultGeometry() throws DataException {
641
        return this.getDefaultFeatureType().getDefaultSRS();
642
    }
643

    
644
    @Override
645
    public FeatureSelection createDefaultFeatureSelection()
646
            throws DataException {
647
        return new DefaultFeatureSelection(this);
648
    }
649

    
650
    @Override
651
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
652
            throws DataException {
653
        if (type.hasOID()) {
654
            return new DefaultFeatureProvider(type,
655
                    this.provider.createNewOID());
656
        }
657
        return new DefaultFeatureProvider(type);
658
    }
659

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

    
695
        }
696

    
697
        if (evaluatedAttr.isEmpty()) {
698
            evaluatedAttr = null;
699
        }
700

    
701
        state.set("evaluatedAttributes", evaluatedAttr);
702
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
703

    
704
    }
705

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

    
745
    private void load(StateInformation state) {
746
        this.featureTypes = new ArrayList();
747
        this.defaultFeatureType = null;
748
        this.featureCount = null;
749

    
750
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
751
        try {
752
            intialize(dataManager, params);
753
        } catch (Throwable th) {
754
            state.setBreakingsCause(th);
755
        }
756

    
757
        try {
758
            DataStoreProvider prov = dataManager.createProvider(
759
                    getStoreProviderServices(),
760
                    params
761
            );
762
            setProvider(prov);
763
        } catch (Throwable th) {
764
            LOGGER.warn("Can't load store from state.", th);
765
            state.setBreakingsCause(th);
766
        }
767
        try {
768
            selection = (FeatureSelection) state.get("selection");
769
        } catch (Throwable th) {
770
            state.setBreakingsCause(th);
771
        }
772

    
773
        try {
774
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
775
            this.transforms.setFeatureStore(this);
776
            for (FeatureStoreTransform transform : this.transforms) {
777
                try {
778
                    transform.setUp();
779
                } catch (Throwable th) {
780
                    state.setBreakingsCause(th);
781
                }
782
            }
783
        } catch (Throwable th) {
784
            state.setBreakingsCause(th);
785
        }
786

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

    
818
                }
819

    
820
            }
821
        } catch (Throwable th) {
822
            state.setBreakingsCause(th);
823
        }
824

    
825
        try {
826
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
827
            FeatureType ftype;
828

    
829
            if (defaultFeatureType == null
830
                    || defaultFeatureType.getId() == null
831
                    || !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
832

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

    
852
        LOGGER.debug("load() broken:{}, {}, {}.",
853
                new Object[]{state.isBroken(), this.getProviderName(), params.toString((Object... args) -> StringUtils.equalsIgnoreCase((CharSequence) args[0], "password")?"******":args[1])}
854
        );
855
    }
856

    
857
    public DataStoreProviderServices getStoreProviderServices() {
858
        return this;
859
    }
860

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

    
883
    private static void registerPersistenceDefinition() {
884
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
885
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
886
            DynStruct definition
887
                    = manager.addDefinition(DefaultFeatureStore.class,
888
                            PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
889
                            + " Persistent definition", null, null);
890
            definition.addDynFieldString("dataStoreName").setMandatory(true)
891
                    .setPersistent(true);
892

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

    
897
            definition.addDynFieldObject("selection")
898
                    .setClassOfValue(FeatureSelection.class).setMandatory(false)
899
                    .setPersistent(true);
900

    
901
            definition.addDynFieldObject("transforms")
902
                    .setClassOfValue(DefaultFeatureStoreTransforms.class)
903
                    .setMandatory(true).setPersistent(true);
904

    
905
            definition.addDynFieldMap("evaluatedAttributes")
906
                    .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
907
                    .setMandatory(false).setPersistent(true);
908

    
909
            definition.addDynFieldString("defaultFeatureTypeId")
910
                    .setMandatory(true).setPersistent(true);
911
        }
912
    }
913

    
914
    private static void registerMetadataDefinition() throws MetadataException {
915
        MetadataManager manager = MetadataLocator.getMetadataManager();
916
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
917
            DynStruct metadataDefinition
918
                    = manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
919
            metadataDefinition.extend(manager
920
                    .getDefinition(DataStore.METADATA_DEFINITION_NAME));
921
        }
922
    }
923

    
924
    //
925
    // ====================================================================
926
    // Gestion de la seleccion
927
    //
928
    @Override
929
    public void setSelection(DataSet selection) throws DataException {
930
        this.setSelection((FeatureSet) selection);
931
    }
932

    
933
    @Override
934
    public DataSet createSelection() throws DataException {
935
        return createFeatureSelection();
936
    }
937

    
938
    @Override
939
    public DataSet getSelection() throws DataException {
940
        return this.getFeatureSelection();
941
    }
942

    
943
    @Override
944
    public void setSelection(FeatureSet selection) throws DataException {
945
        setSelection(selection, true);
946
    }
947

    
948
    public void setSelection(FeatureSet selection, boolean undoable)
949
            throws DataException {
950
        if (selection == null) {
951
            if (undoable) {
952
                throw new SelectionNotAllowedException(getName());
953
            }
954

    
955
        } else {
956
            if (selection.equals(this.selection)) {
957
                return;
958
            }
959
            if (!selection.isFromStore(this)) {
960
                throw new SelectionNotAllowedException(getName());
961
            }
962
        }
963

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

    
1005
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1006
    }
1007

    
1008
    @Override
1009
    public FeatureSelection createFeatureSelection() throws DataException {
1010
        FeatureType featureType = this.getDefaultFeatureTypeQuietly();
1011
        if( featureType!=null ) {
1012
            Tags tags = featureType.getTags();
1013
            if( tags.has(DataManager.DAL_USE_LARGE_SELECTION) ) {
1014
                boolean useLargeSelection = tags.getBoolean(DataManager.DAL_USE_LARGE_SELECTION,true);
1015
                if( useLargeSelection ) {
1016
                    return createLargeFeatureSelection();
1017
                }
1018
                return this.provider.createFeatureSelection();
1019
            }
1020
        }
1021
        long maxSize = dataManager.getMaxSizeForSmallFeatureSelection();
1022
        if (this.provider.getFeatureCount() > maxSize) {
1023
            return createLargeFeatureSelection();
1024
        }
1025
        return this.provider.createFeatureSelection();
1026
    }
1027

    
1028
    @Override
1029
    public FeatureSelection createLargeFeatureSelection() throws DataException {
1030
        return new LargeFeatureSelection(this);
1031

    
1032
    }
1033

    
1034
    @Override
1035
    public FeatureSelection createMemoryFeatureSelection() throws DataException {
1036
        return this.provider.createFeatureSelection();
1037
    }
1038

    
1039
    @Override
1040
    public FeatureSelection getFeatureSelection() throws DataException {
1041
        if (selection == null) {
1042
            this.selection = createFeatureSelection();
1043
            this.selection.addObserver(this);
1044
        }
1045
        return selection;
1046
    }
1047

    
1048
    @Override
1049
    public FeatureSelection getFeatureSelectionQuietly() {
1050
        try {
1051
            return this.getFeatureSelection();
1052
        } catch (DataException ex) {
1053
            return FeatureSelection.EMTPY_FEATURE_SELECTION;
1054
        }
1055
    }
1056
    
1057
    
1058

    
1059
    @Override
1060
    public boolean isFeatureSelectionEmpty() {
1061
        if( selection == null ) {
1062
            return true;
1063
        }
1064
        return selection.isEmpty();
1065
    }
1066
    
1067
    //
1068
    // ====================================================================
1069
    // Gestion de notificaciones
1070
    //
1071
    @Override
1072
    public FeatureStoreNotification notifyChange(FeatureStoreNotification storeNotification) {
1073
        if (delegateObservable != null) {
1074
            try {
1075
                delegateObservable.notifyObservers(storeNotification);
1076
            } catch (Throwable ex) {
1077
                LOGGER.warn("Problems notifying changes in the store '" + this.getName() + " (" + storeNotification.getType() + ").", ex);
1078
            }
1079
        }
1080
        return storeNotification;
1081
    }
1082

    
1083
    @Override
1084
    public FeatureStoreNotification notifyChange(String notification) {
1085
        return notifyChange(
1086
                new DefaultFeatureStoreNotification(
1087
                        this, notification, 
1088
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1089
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode
1090
                )
1091
        );
1092
    }
1093

    
1094
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode) {
1095
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode));
1096
    }
1097

    
1098
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode, int editMode) {
1099
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode, editMode));
1100
    }
1101

    
1102
    public FeatureStoreNotification notifyChange(String notification,
1103
//            String editingSessionCode,
1104
            Iterator<FeatureReference> deleteds,
1105
            Iterator<EditableFeature> inserteds,
1106
            Iterator<EditableFeature> updateds,
1107
            Iterator<FeatureTypeChanged> featureTypesChanged,
1108
            boolean isSelectionCompromised) {
1109
        return notifyChange(
1110
                new DefaultFeatureStoreNotification(
1111
                        this, notification, 
1112
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1113
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1114
                        deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised
1115
                )
1116
        );
1117
    }
1118

    
1119
    @Override
1120
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
1121
        Feature f = null;
1122
        if (data != null) {
1123
            try {
1124
                f = createFeature(data);
1125
            } catch (Throwable ex) {
1126
                LOGGER.warn("Problems creating a feature to notifying changes in the store '" + this.getName() + " (" + notification + ").", ex);
1127
            }
1128
        }
1129
        return notifyChange(notification, f);
1130
    }
1131

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

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

    
1154
    public FeatureStoreNotification notifyChange(String notification, Command command) {
1155
        return notifyChange(
1156
                new DefaultFeatureStoreNotification(
1157
                        this, notification, 
1158
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1159
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1160
                        command
1161
                )
1162
        );
1163
    }
1164

    
1165
    public FeatureStoreNotification notifyChange(String notification, EditableFeatureType type) {
1166
        return notifyChange(
1167
                new DefaultFeatureStoreNotification(
1168
                        this, notification, 
1169
                        this.editingSessionCode==null?this.lastEditingSessionCode:this.editingSessionCode,
1170
                        this.mode == FeatureStore.MODE_QUERY?this.lastMode:this.mode,
1171
                        type
1172
                )
1173
        );
1174
    }
1175

    
1176
    @Override
1177
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
1178
        return notifyChange(
1179
                new DefaultFeatureStoreNotification(
1180
                        this, DataStoreNotification.RESOURCE_CHANGED
1181
                )
1182
        );
1183
    }
1184

    
1185
    //
1186
    // ====================================================================
1187
    // Gestion de bloqueos
1188
    //
1189
    @Override
1190
    public boolean isLocksSupported() {
1191
        return this.provider.isLocksSupported();
1192
    }
1193

    
1194
    @Override
1195
    public FeatureLocks getLocks() throws DataException {
1196
        if (!this.provider.isLocksSupported()) {
1197
            LOGGER.warn("Locks not supported");
1198
            return null;
1199
        }
1200
        if (locks == null) {
1201
            this.locks = this.provider.createFeatureLocks();
1202
        }
1203
        return locks;
1204
    }
1205

    
1206
    //
1207
    // ====================================================================
1208
    // Interface Observable
1209
    //
1210
    @Override
1211
    public void disableNotifications() {
1212
        this.delegateObservable.disableNotifications();
1213

    
1214
    }
1215

    
1216
    @Override
1217
    public void enableNotifications() {
1218
        this.delegateObservable.enableNotifications();
1219
    }
1220

    
1221
    @Override
1222
    public void beginComplexNotification() {
1223
        this.delegateObservable.beginComplexNotification();
1224

    
1225
    }
1226

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

    
1231
    }
1232

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

    
1240
    @Override
1241
    public void deleteObserver(Observer observer) {
1242
        if (delegateObservable != null) {
1243
            this.delegateObservable.deleteObserver(observer);
1244
        }
1245
    }
1246

    
1247
    @Override
1248
    public void deleteObservers() {
1249
        this.delegateObservable.deleteObservers();
1250

    
1251
    }
1252

    
1253
    //
1254
    // ====================================================================
1255
    // Interface Observer
1256
    //
1257
    // Usado para observar:
1258
    // - su seleccion
1259
    // - sus bloqueos
1260
    // - sus recursos
1261
    //
1262
    @Override
1263
    public void update(Observable observable, Object notification) {
1264
        if (observable instanceof FeatureSet) {
1265
            if (observable == this.selection) {
1266
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1267
            } else if (observable == this.locks) {
1268
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1269
            }
1270

    
1271
        } else if (observable instanceof FeatureStoreProvider) {
1272
            if (observable == this.provider) {
1273

    
1274
            }
1275
        } else if (observable instanceof FeatureReferenceSelection) {
1276
            if (notification instanceof String) {
1277
                this.notifyChange((String) notification);
1278
            }
1279
        }
1280
    }
1281

    
1282
    //
1283
    // ====================================================================
1284
    // Edicion
1285
    //
1286
    private void newVersionOfUpdate() {
1287
        this.versionOfUpdate++;
1288
    }
1289

    
1290
    private long currentVersionOfUpdate() {
1291
        return this.versionOfUpdate;
1292
    }
1293

    
1294
    private void checkInEditingMode() throws NeedEditingModeException {
1295
        if (mode != MODE_FULLEDIT) {
1296
            throw new NeedEditingModeException(this.getName());
1297
        }
1298
    }
1299

    
1300
    private void checkNotInAppendMode() throws IllegalStateException {
1301
        if (mode == MODE_APPEND) {
1302
            throw new IllegalStateException("Error: store "
1303
                    + this.getFullName() + " is in append mode");
1304
        }
1305
    }
1306

    
1307
    private void checkIsOwnFeature(Feature feature)
1308
            throws IllegalFeatureException {
1309
        if (((DefaultFeature) feature).getStore() != this) {
1310
            throw new IllegalFeatureException(this.getName());
1311
        }
1312
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1313
        // fixFeatureType((DefaultFeatureType) feature.getType());
1314
    }
1315

    
1316
    private void exitEditingMode() {
1317
        if (commands != null) {
1318
            try {
1319
                commands.clear();
1320
            } catch (Exception ex) {
1321
                LOGGER.trace("Can't clear commands", ex);
1322
            }
1323
            commands = null;
1324
        }
1325

    
1326
        if (featureTypeManager != null) {
1327
            DisposeUtils.disposeQuietly(featureTypeManager);
1328
            featureTypeManager = null;
1329

    
1330
        }
1331

    
1332
        // TODO implementar un dispose para estos dos
1333
        featureManager = null;
1334
        if (spatialManager != null) {
1335
            spatialManager.clear();
1336
        }
1337
        spatialManager = null;
1338

    
1339
        featureCount = null;
1340

    
1341
        this.lastMode = this.mode;
1342
        mode = MODE_QUERY;
1343
        hasStrongChanges = true; // Lo deja a true por si las moscas
1344

    
1345
        this.lastEditingSessionCode = this.editingSessionCode;
1346
        this.editingSessionCode = null;
1347
        
1348
        if( StringUtils.equalsIgnoreCase(DatabaseWorkspaceManager.TABLE_RESOURCES_NAME, this.getName()) ) {
1349
            // Es un poco drastico, pero cuando terminamos edicion de la tabla
1350
            // GVSIGD_RESOURCES, borraremos las cache de todos los recursos por
1351
            // que no sabemos si se ha modificado alguno y ha quedado obsoleto.
1352
            DALLocator.getDataManager().clearAllCachedResources();
1353
        }
1354
    }
1355

    
1356
    @Override
1357
    public int getSubmode() {
1358
        return this.submode;
1359
    }
1360

    
1361
    @Override
1362
    synchronized public void edit() throws DataException {
1363
        edit(MODE_FULLEDIT);
1364
    }
1365
    
1366
    @Override
1367
    synchronized public void edit(int mode) throws DataException {
1368
        this.edit(mode, SUBMODE_NONE);
1369
    }
1370

    
1371
    @Override
1372
    synchronized public void edit(int mode, int submode) throws DataException {
1373
        LOGGER.debug("Starting editing in mode: {}", mode);
1374
        if (this.mode != MODE_QUERY) {
1375
            throw new AlreadyEditingException(this.getName());
1376
        }
1377
        FeatureType ftype = this.getDefaultFeatureType();
1378
        String newSessionCode = this.createUniqueID();
1379
        try {
1380
            if (!this.provider.supportsAppendMode()) {
1381
                mode = MODE_FULLEDIT;
1382
            }
1383
            if (!this.canBeEdited()) {
1384
                 throw new IllegalStateException(this.getName());
1385
            }
1386
            switch (mode) {
1387
                case MODE_QUERY:
1388
                    throw new IllegalStateException(this.getName());
1389

    
1390
                case MODE_FULLEDIT:
1391
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1392
                            newSessionCode, mode).isCanceled()) {
1393
                        return;
1394
                    }
1395
                    this.editingSessionCode = newSessionCode;
1396
                    invalidateIndexes();
1397
                    featureManager = new FeatureManager(this);
1398
                    featureTypeManager = new FeatureTypeManager(this);
1399
                    spatialManager = new SpatialManager(this);
1400

    
1401
                    commands = new DefaultFeatureCommandsStack(
1402
                            this, featureManager,
1403
                            spatialManager, featureTypeManager);
1404
                    this.mode = MODE_FULLEDIT;
1405
                    this.submode = submode;
1406
                    hasStrongChanges = false;
1407
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING, newSessionCode, this.mode);
1408
                    break;
1409

    
1410
                case MODE_APPEND:
1411
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1412
                            newSessionCode, mode).isCanceled()) {
1413
                        return;
1414
                    }
1415
                    this.editingSessionCode = newSessionCode;
1416
                    invalidateIndexes();
1417
                    this.provider.beginAppend(submode);
1418
                    this.mode = MODE_APPEND;
1419
                    this.submode = submode;
1420
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1421
                            newSessionCode, this.mode);
1422
                    break;
1423
                case MODE_PASS_THROUGH:
1424
                    if (!this.provider.supportsPassThroughMode()) {
1425
                        throw new IllegalStateException(this.getName());
1426
                    }
1427
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1428
                            newSessionCode, mode).isCanceled()) {
1429
                        return;
1430
                    }
1431
                    this.editingSessionCode = newSessionCode;
1432
                    invalidateIndexes();
1433
                    this.mode = MODE_PASS_THROUGH;
1434
                    this.submode = submode;
1435
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1436
                            newSessionCode, this.mode);
1437
                    break;
1438

    
1439
            }
1440
        } catch (Exception e) {
1441
            try {
1442
                if (this.mode != MODE_QUERY) {
1443
                    exitEditingMode();
1444
                }
1445
                notifyChange(FeatureStoreNotification.FAILED_STARTEDITING,
1446
                        newSessionCode, mode);
1447
            } catch (Throwable th) {
1448
                LOGGER.warn("Can't cleanup after error in start editing.", th);
1449
            }
1450
            throw new StoreEditException(e, this.getName());
1451
        }
1452
    }
1453

    
1454
    private void invalidateIndexes() {
1455
        setIndexesValidStatus(false);
1456
    }
1457

    
1458
    private void setIndexesValidStatus(boolean valid) {
1459
        FeatureIndexes theIndexes = getIndexes();
1460
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1461
                ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1462
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1463
            FeatureIndex index = (FeatureIndex) iterator.next();
1464
            if (index instanceof FeatureIndexProviderServices) {
1465
                FeatureIndexProviderServices indexServices
1466
                        = (FeatureIndexProviderServices) index;
1467
                indexServices.setValid(valid);
1468
            }
1469
        }
1470
    }
1471

    
1472
    private void updateIndexes() throws FeatureIndexException {
1473
        FeatureIndexes theIndexes = getIndexes();
1474
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1475
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1476
            FeatureIndex index = (FeatureIndex) iterator.next();
1477
            if (index instanceof FeatureIndexProviderServices) {
1478
                FeatureIndexProviderServices indexServices
1479
                        = (FeatureIndexProviderServices) index;
1480
                indexServices.fill(true, null);
1481
            }
1482
        }
1483
    }
1484

    
1485
    private void waitForIndexes() {
1486
        FeatureIndexes theIndexes = getIndexes();
1487
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1488
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1489
            FeatureIndex index = (FeatureIndex) iterator.next();
1490
            if (index instanceof FeatureIndexProviderServices) {
1491
                FeatureIndexProviderServices indexServices
1492
                        = (FeatureIndexProviderServices) index;
1493
                indexServices.waitForIndex();
1494
            }
1495
        }
1496
    }
1497

    
1498
    private void disposeIndexes() {
1499
        FeatureIndexes theIndexes = getIndexes();
1500
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1501
        if (theIndexes == null) {
1502
            return;
1503
        }
1504
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1505
            FeatureIndex index = (FeatureIndex) iterator.next();
1506
            if (index instanceof FeatureIndexProviderServices) {
1507
                FeatureIndexProviderServices indexServices
1508
                        = (FeatureIndexProviderServices) index;
1509
                indexServices.dispose();
1510
            }
1511
        }
1512
    }
1513

    
1514
    @Override
1515
    public boolean isEditing() {
1516
        return mode == MODE_FULLEDIT;
1517
    }
1518

    
1519
    @Override
1520
    public boolean isAppending() {
1521
        return mode == MODE_APPEND;
1522
    }
1523

    
1524
    @Override
1525
    synchronized public void update(EditableFeatureType type)
1526
            throws DataException {
1527
        try {
1528
            if (type == null) {
1529
                throw new NullFeatureTypeException(getName());
1530
            }
1531

    
1532
            switch (this.mode) {
1533
                case MODE_QUERY:
1534
                    if (type.hasOnlyMetadataChanges(this.defaultFeatureType)) {
1535
                        if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1536
                            return;
1537
                        }
1538
                        FeatureType theType = type.getNotEditableCopy();
1539
                        if (defaultFeatureType.getId().equals(theType.getId())) {
1540
                            defaultFeatureType = theType;
1541
                        }
1542
                        List newtypes = new ArrayList();
1543
                        for (FeatureType featureType : this.featureTypes) {
1544
                            if (featureType.getId().equals(theType.getId())) {
1545
                                newtypes.add(theType);
1546
                            } else {
1547
                                newtypes.add(featureType);
1548
                            }
1549
                        }
1550
                        this.featureTypes = newtypes;
1551
                        saveDALFile();
1552
                        notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1553
                    }
1554

    
1555
                    break;
1556
                case MODE_FULLEDIT:
1557
                    if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1558
                        return;
1559
                    }
1560
                    newVersionOfUpdate();
1561

    
1562
                    FeatureType oldt = type.getSource().getCopy();
1563
                    FeatureType newt = type.getCopy();
1564
                    commands.update(newt, oldt);
1565
                    hasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1566
                    notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1567
                    break;
1568
                case MODE_APPEND:
1569
                case MODE_PASS_THROUGH:
1570
                    throw new NeedEditingModeException(this.getName());
1571

    
1572
            }
1573
        } catch (Exception e) {
1574
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1575
        }
1576
    }
1577
    
1578
    @Override
1579
    public void delete(Feature feature) throws DataException {
1580
        switch (this.mode) {
1581
            case MODE_PASS_THROUGH:
1582
                checkIsOwnFeature(feature);
1583
                if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1584
                    return;
1585
                }
1586
                this.provider.passThroughDelete((FeatureReferenceProviderServices) feature.getReference());
1587
                notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1588
                break;
1589
            default:
1590
                this.commands.delete(feature);
1591
                break;
1592

    
1593
        }
1594
    }
1595

    
1596
    @Override
1597
    public void delete(String filter) {
1598
        if (StringUtils.isBlank(filter)) {
1599
            return;
1600
        }
1601
        this.delete(ExpressionUtils.createExpression(filter));
1602
    }
1603

    
1604
    @Override
1605
    public void delete(Expression filter) {
1606
        if (filter == null) {
1607
            return;
1608
        }
1609
        boolean pendingFinishEditing = false;
1610
        DisposableFeatureSetIterable features = null;
1611
        try {
1612
            switch (this.mode) {
1613
                case MODE_QUERY:
1614
                    pendingFinishEditing = true;
1615
                    this.edit();
1616
                    break;
1617
                case MODE_APPEND:
1618
                    throw new IllegalStateException("Delete not allowed in append mode.");
1619
                case MODE_FULLEDIT:
1620
                    break;
1621
                case MODE_PASS_THROUGH:
1622
                    if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, filter).isCanceled()) {
1623
                        return;
1624
                    }
1625
                    this.provider.passThroughDelete(filter);
1626
                    notifyChange(FeatureStoreNotification.AFTER_DELETE, filter);                    
1627
                    return;
1628
                default:
1629
                    throw new IllegalStateException("Mode " + this.mode + " not supported.");
1630
            }
1631

    
1632
            FeatureSet fset = this.getFeatureSet(filter);
1633
            features = fset.iterable();
1634
            for (Feature f : features) {
1635
                fset.delete(f);
1636
            }
1637
        } catch (DataException ex) {
1638
            throw new DataRuntimeException(ex.getFormatString(), ex.getMessageKey(), ex.getCode()) {
1639
            };
1640
        } catch (Exception ex) {
1641
            throw new RuntimeException("Can't delete features (" + filter.getPhrase() + ").", ex);
1642
        } finally {
1643
            if (pendingFinishEditing) {
1644
                this.finishEditingQuietly();
1645
            }
1646
            DisposeUtils.disposeQuietly(features);
1647
        }
1648
    }
1649

    
1650
    synchronized public void doDelete(Feature feature) throws DataException {
1651
        if (feature == null) {
1652
            throw new IllegalArgumentException("feature argument can't be null.");
1653
        }
1654
        try {
1655
            checkInEditingMode();
1656
            checkIsOwnFeature(feature);
1657
            if (feature instanceof EditableFeature && !((EditableFeature)feature).isUpdatable()) {
1658
                //La feature no est? persistida en disco
1659
                throw new StoreDeleteEditableFeatureException(getName());
1660
            }
1661
            if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1662
                return;
1663
            }
1664

    
1665
            //Update the featureManager and the spatialManager
1666
            featureManager.delete(feature);
1667
            spatialManager.deleteFeature(feature);
1668

    
1669
            newVersionOfUpdate();
1670
            hasStrongChanges = true;
1671
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1672
        } catch (Exception e) {
1673
            throw new StoreDeleteFeatureException(e, this.getName());
1674
        }
1675
    }
1676

    
1677
    @Override
1678
    public synchronized void insert(FeatureSet set) throws DataException {
1679
        switch (mode) {
1680
            case MODE_QUERY:
1681
                throw new NeedEditingModeException(this.getName());
1682

    
1683
            case MODE_APPEND:
1684
            case MODE_FULLEDIT:
1685
            case MODE_PASS_THROUGH:
1686
            try {
1687
                set.accept((Object obj) -> {
1688
                    EditableFeature ef = createNewFeature((Feature) obj);
1689
                    insert(ef);
1690
                });
1691
            } catch (BaseException ex) {
1692
                throw new StoreInsertFeatureException(ex, this.getName());
1693
            }
1694
            break;
1695
        }
1696
    }
1697

    
1698
    private static EditableFeature lastChangedFeature = null;
1699

    
1700
    @Override
1701
    public synchronized void insert(EditableFeature feature)
1702
            throws DataException {
1703
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1704
        try {
1705
            switch (mode) {
1706
                case MODE_QUERY:
1707
                    throw new NeedEditingModeException(this.getName());
1708

    
1709
                case MODE_APPEND:
1710
                    checkIsOwnFeature(feature);
1711
                    if (feature.isUpdatable()) {
1712
                        throw new NoNewFeatureInsertException(this.getName());
1713
                    }
1714
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1715
                        return;
1716
                    }
1717
                    this.featureCount = null;
1718
                    feature.validate(CHECK_RULES_AT_EDITING);
1719
                    provider.append(((DefaultEditableFeature) feature).getData());
1720
                    hasStrongChanges = true;
1721
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1722
                    break;
1723

    
1724
                case MODE_FULLEDIT:
1725
                    if( this.submode == SUBMODE_MERGE ) {
1726
                        Expression filter = feature.createFilter();
1727
                        Feature f = this.findFirst(filter);
1728
                        if( f == null ) {
1729
                            this.insert(feature);
1730
                        } else {
1731
                            this.update(feature);
1732
                        }
1733
                    } else {
1734
                        if (feature.isUpdatable()) {
1735
                            throw new NoNewFeatureInsertException(this.getName());
1736
                        }
1737
                        feature.validate(CHECK_RULES_AT_EDITING);
1738
                        commands.insert(feature);
1739
                    }
1740
                    break;
1741

    
1742
                case MODE_PASS_THROUGH:
1743
                    checkIsOwnFeature(feature);
1744
                    if (feature.isUpdatable()) {
1745
                        throw new NoNewFeatureInsertException(this.getName());
1746
                    }
1747
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1748
                        return;
1749
                    }
1750
                    feature.validate(CHECK_RULES_AT_EDITING);
1751
                    if( this.submode == SUBMODE_MERGE ) {
1752
                        this.provider.passThroughInsertOrUpdate(((DefaultEditableFeature) feature).getData());
1753
                    } else {
1754
                        this.provider.passThroughInsert(((DefaultEditableFeature) feature).getData());
1755
                    }
1756
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1757
                    break;
1758
            }
1759
        } catch (Exception e) {
1760
            throw new StoreInsertFeatureException(e, this.getName());
1761
        }
1762
    }
1763

    
1764
    synchronized public void doInsert(EditableFeature feature)
1765
            throws DataException {
1766
        checkIsOwnFeature(feature);
1767

    
1768
        waitForIndexes();
1769

    
1770
        if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1771
            return;
1772
        }
1773
        newVersionOfUpdate();
1774
        if ((lastChangedFeature == null)
1775
                || (lastChangedFeature.getSource() != feature.getSource())) {
1776
            lastChangedFeature = feature;
1777
            feature.validate(CHECK_RULES_AT_EDITING);
1778
            lastChangedFeature = null;
1779
        }
1780
        //Update the featureManager and the spatialManager
1781
        ((DefaultFeature) feature).setInserted(true);
1782
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1783

    
1784
        featureManager.add(feature);
1785
        spatialManager.insertFeature(newFeature);
1786

    
1787
        hasStrongChanges = true;
1788
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1789
    }
1790

    
1791
    @Override
1792
    public void update(EditableFeature feature)
1793
            throws DataException {
1794
        switch (this.mode) {
1795
            case MODE_PASS_THROUGH:
1796
                checkIsOwnFeature(feature);
1797
                if (!feature.isUpdatable()) {
1798
                    throw new NoNewFeatureInsertException(this.getName());
1799
                }
1800
                if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1801
                    return;
1802
                }
1803
                feature.validate(CHECK_RULES_AT_EDITING);
1804
                this.provider.passThroughUpdate(((DefaultEditableFeature) feature).getData());
1805
                notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1806
                break;
1807
            case MODE_FULLEDIT:
1808
                if(!feature.getType().supportReferences()){
1809
                    throw new UnsupportedOperationException("Can't update store in full edit mode without references support.");
1810
                }
1811
                if (feature.isUpdatable()) {
1812
                    commands.update(feature, feature.getSource());
1813
                    return;
1814
                }
1815
                // FIXME: Deberiamos lanzar aqui un error en lugar de hacer el insert.
1816
                //        O lanzar un mensaje al log?
1817
                insert(feature);
1818
                break;
1819
            default:
1820
                throw new NeedEditingModeException(this.getName());
1821
        }
1822
    }
1823

    
1824
    @Override
1825
    public void update(Object... parameters) throws DataException {
1826
        if (parameters.length == 1) {
1827
            Object param0 = parameters[0];
1828
            if (param0 instanceof EditableFeature) {
1829
                this.update((EditableFeature) param0);
1830
            } else if (param0 instanceof EditableFeatureType) {
1831
                this.update((EditableFeatureType) param0);
1832
            } else {
1833
                throw new IllegalArgumentException("Type of first parameter isn't supported");
1834
            }
1835
            return;
1836
        }
1837

    
1838
        Expression filter = null;
1839
        long end = parameters.length;
1840
        if (parameters.length % 2 == 1) { //IMPAR
1841
            Object param = parameters[parameters.length - 1];
1842
            if (param != null) {
1843
                if (param instanceof Expression) {
1844
                    filter = (Expression) param;
1845
                } else {
1846
                    filter = ExpressionUtils.createExpression(param.toString());
1847
                }
1848
            }
1849
        } else {
1850
            end = parameters.length - 1;
1851
        }
1852

    
1853
        switch (this.mode) {
1854
            case MODE_PASS_THROUGH:
1855
                this.provider.passThroughUpdate(
1856
                        //                    this.getName(), 
1857
                        parameters,
1858
                        filter);
1859
                break;
1860
            case MODE_FULLEDIT:
1861
                FeatureSet set = this.getFeatureSet(filter);
1862
                DisposableIterator it = set.fastIterator();
1863
                while (it.hasNext()) {
1864
                    Feature feature = (Feature) it.next();
1865
                    EditableFeature ef = feature.getEditable();
1866
                    for (int i = 0; i < end; i += 2) {
1867
                        String name = (String) parameters[i];
1868
                        Object value = parameters[i + 1];
1869
                        ef.set(name, value);
1870
                    }
1871
                    set.update(ef);
1872
                }
1873
                DisposeUtils.disposeQuietly(it);
1874
                DisposeUtils.disposeQuietly(set);
1875
                break;
1876
            default:
1877
                throw new NeedEditingModeException(this.getName());
1878
        }
1879
    }
1880

    
1881
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1882
            throws DataException {
1883
        try {
1884
            checkInEditingMode();
1885
            checkIsOwnFeature(feature);
1886
            if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1887
                return;
1888
            }
1889
            newVersionOfUpdate();
1890
            if ((lastChangedFeature == null)
1891
                    || (lastChangedFeature.getSource() != feature.getSource())) {
1892
                lastChangedFeature = feature;
1893
                feature.validate(CHECK_RULES_AT_EDITING);
1894
                lastChangedFeature = null;
1895
            }
1896

    
1897
            //Update the featureManager and the spatialManager
1898
            Feature newf = feature.getNotEditableCopy();
1899
            featureManager.update(feature, oldFeature);
1900
            spatialManager.updateFeature(newf, oldFeature);
1901

    
1902
            hasStrongChanges = true;
1903
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1904
        } catch (Exception e) {
1905
            throw new StoreUpdateFeatureException(e, this.getName());
1906
        }
1907
    }
1908

    
1909
    @Override
1910
    synchronized public void redo() throws RedoException {
1911
        Command redo = commands.getNextRedoCommand();
1912
        try {
1913
            checkInEditingMode();
1914
        } catch (NeedEditingModeException ex) {
1915
            throw new RedoException(redo, ex);
1916
        }
1917
        if (notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled()) {
1918
            return;
1919
        }
1920
        newVersionOfUpdate();
1921
        commands.redo();
1922
        hasStrongChanges = true;
1923
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1924
    }
1925

    
1926
    @Override
1927
    synchronized public void undo() throws UndoException {
1928
        Command undo = commands.getNextUndoCommand();
1929
        try {
1930
            checkInEditingMode();
1931
        } catch (NeedEditingModeException ex) {
1932
            throw new UndoException(undo, ex);
1933
        }
1934
        if (notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled()) {
1935
            return;
1936
        }
1937
        newVersionOfUpdate();
1938
        commands.undo();
1939
        hasStrongChanges = true;
1940
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1941
    }
1942

    
1943
    @Override
1944
    public List getRedoInfos() {
1945
        if (isEditing() && (commands != null)) {
1946
            return commands.getRedoInfos();
1947
        } else {
1948
            return null;
1949
        }
1950
    }
1951

    
1952
    @Override
1953
    public List getUndoInfos() {
1954
        if (isEditing() && (commands != null)) {
1955
            return commands.getUndoInfos();
1956
        } else {
1957
            return null;
1958
        }
1959
    }
1960

    
1961
    public synchronized FeatureCommandsStack getCommandsStack()
1962
            throws DataException {
1963
        checkInEditingMode();
1964
        return commands;
1965
    }
1966

    
1967
    @Override
1968
    public boolean cancelEditingQuietly() {
1969
        try {
1970
            this.cancelEditing();
1971
            return true;
1972
        } catch (Exception ex) {
1973
            LOGGER.debug("Can't cancel editing", ex);
1974
            return false;
1975
        }
1976
    }
1977

    
1978
    @Override
1979
    synchronized public void cancelEditing() throws DataException {
1980
        try {
1981
            switch (mode) {
1982
                case MODE_QUERY:
1983
                    throw new NeedEditingModeException(this.getName());
1984

    
1985
                case MODE_APPEND:
1986
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1987
                        return;
1988
                    }
1989
                    provider.abortAppend();
1990
                    exitEditingMode();
1991
                    ((FeatureSelection) this.getSelection()).deselectAll();
1992
                    updateIndexes();
1993
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1994
                    break;
1995

    
1996
                case MODE_FULLEDIT:
1997
                    boolean clearSelection = this.hasStrongChanges;
1998
                    if (this.selection instanceof FeatureReferenceSelection) {
1999
                        clearSelection = this.hasStrongChanges || this.featureManager.hasNews();
2000
                    }
2001
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
2002
                        return;
2003
                    }
2004
                    exitEditingMode();
2005
                    if (clearSelection) {
2006
                        ((FeatureSelection) this.getSelection()).deselectAll();
2007
                    }
2008
                    updateIndexes();
2009
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
2010
                    break;
2011

    
2012
                case MODE_PASS_THROUGH:
2013
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
2014
                        return;
2015
                    }
2016
                    exitEditingMode();
2017
                    ((FeatureSelection) this.getSelection()).deselectAll();
2018
                    updateIndexes();
2019
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
2020
                    break;
2021
            }
2022
        } catch (Exception e) {
2023
            throw new StoreCancelEditingException(e, this.getName());
2024
        }
2025
    }
2026

    
2027
    @Override
2028
    public boolean finishEditingQuietly() {
2029
        try {
2030
            this.finishEditing();
2031
            return true;
2032
        } catch (Exception ex) {
2033
            LOGGER.debug("Can't finish editing", ex);
2034
            return false;
2035
        }
2036
    }
2037

    
2038
    
2039
    @Override
2040
    synchronized public void finishEditing() throws DataException {
2041
        LOGGER.debug("finish editing of mode: {}", mode);
2042
        LocalTransaction trans = new LocalTransaction(this.dataManager, this.getTransaction());
2043
        try {
2044
            switch (mode) {
2045
                case MODE_QUERY:
2046
                    throw new NeedEditingModeException(this.getName());
2047

    
2048
                case MODE_APPEND:
2049
                    if (selection != null) {
2050
                        selection = null;
2051
                    }
2052
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2053
                        return;
2054
                    }
2055
                    trans.begin();
2056
                    trans.add(this);
2057
                    saveDALFile();
2058
                    provider.endAppend();
2059
                    exitEditingMode();
2060
                    loadDALFile();
2061
                    updateIndexes();
2062
                    trans.commit();
2063
                    trans.close();
2064
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2065
                    break;
2066

    
2067
                case MODE_FULLEDIT:
2068
                    if (featureManager.hasChanges() || featureTypeManager.hasChanges()) {
2069
                        if (hasStrongChanges && !this.allowWrite()) {
2070
                            throw new WriteNotAllowedException(getName());
2071
                        }
2072
                        if (notifyChange(FeatureStoreNotification.PREPARING_FINISHEDITING).isCanceled()) {
2073
                            return;
2074
                        }
2075
                        if (hasStrongChanges) {
2076
                            validateFeaturesAtFinishEditing();
2077
                        }
2078
                        if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING,
2079
                                featureManager.getDeleted(),
2080
                                featureManager.getInsertedFeatures(),
2081
                                featureManager.getUpdatedFeatures(),
2082
                                featureTypeManager.getFeatureTypesChanged().iterator(),
2083
                                featureManager.isSelectionCompromised()).isCanceled()) {
2084
                            return;
2085
                        }
2086
                        trans.begin();
2087
                        trans.add(this);
2088
                        saveDALFile();
2089
                        if (featureManager.isSelectionCompromised() && selection != null) {
2090
                            selection = null;
2091
                        }
2092
                        if (hasStrongChanges) {
2093
                            // This will throw a PerformEditingException if the provider
2094
                            // does not accept the changes (for example, an invalid field name)
2095
                            provider.performChanges(featureManager.getDeleted(),
2096
                                    featureManager.getInserted(),
2097
                                    featureManager.getUpdated(),
2098
                                    featureTypeManager.getFeatureTypesChanged().iterator());
2099
                        }
2100
                        exitEditingMode();
2101
                        loadDALFile();
2102
                        updateIndexes();
2103
                        trans.commit();
2104
                        trans.close();
2105
                    } else {
2106
                        exitEditingMode();
2107
                    }
2108
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2109
                    break;
2110
                case MODE_PASS_THROUGH:
2111
                    if (selection != null) {
2112
                        selection = null;
2113
                    }
2114
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2115
                        return;
2116
                    }
2117
                    exitEditingMode();
2118
                    updateIndexes();
2119
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2120
                    break;
2121
            }
2122
        } catch (ValidateFeaturesException | WriteNotAllowedException ex) {
2123
            // Don't notify failed.
2124
            trans.abortQuietly();
2125
            throw ex;
2126
        } catch (PerformEditingException pee) {
2127
            trans.abortQuietly();
2128
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2129
            throw new WriteException(provider.getSourceId().toString(), pee);
2130
        } catch (Exception e) {
2131
            trans.abortQuietly();
2132
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2133
            throw new FinishEditingException(e);
2134
        } finally {
2135
            trans.closeQuietly();
2136
        }
2137
    }
2138
    
2139
    @Override
2140
    public String getEditingSession() {
2141
        return this.editingSessionCode;
2142
    }
2143

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

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

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

    
2240
                case MODE_APPEND:
2241
                    this.provider.endAppend();
2242
                    exitEditingMode();
2243
                    invalidateIndexes();
2244
                    this.provider.beginAppend();
2245
                    break;
2246

    
2247
                case MODE_FULLEDIT:
2248
                    if (hasStrongChanges && !this.allowWrite()) {
2249
                        throw new WriteNotAllowedException(getName());
2250
                    }
2251
                    // FIXME: OOhh!!!! no se disparan eventos, VCSGis no se entera de estos cambios.
2252
                    if (hasStrongChanges) {
2253
                        validateFeaturesAtFinishEditing();
2254
                        provider.performChanges(featureManager.getDeleted(),
2255
                                featureManager.getInserted(),
2256
                                featureManager.getUpdated(),
2257
//                                removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2258
                                featureTypeManager.getFeatureTypesChanged().iterator());
2259
                    }
2260
                    invalidateIndexes();
2261
                    featureManager = new FeatureManager(this);
2262
                    featureTypeManager = new FeatureTypeManager(this);
2263
                    spatialManager = new SpatialManager(this);
2264

    
2265
                    commands
2266
                            = new DefaultFeatureCommandsStack(this, featureManager,
2267
                                    spatialManager, featureTypeManager);
2268
                    featureCount = null;
2269
                    hasStrongChanges = false;
2270
                    break;
2271
            }
2272
        } catch (Exception e) {
2273
            throw new FinishEditingException(e);
2274
        }
2275
    }
2276

    
2277
    @Override
2278
    synchronized public boolean canCommitChanges() throws DataException {
2279
        if (!this.allowWrite()) {
2280
            return false;
2281
        }
2282
        switch (mode) {
2283
            default:
2284
            case MODE_QUERY:
2285
                return false;
2286

    
2287
            case MODE_APPEND:
2288
                return true;
2289

    
2290
            case MODE_FULLEDIT:
2291
                List types = this.getFeatureTypes();
2292
                for (int i = 0; i < types.size(); i++) {
2293
                    Object type = types.get(i);
2294
                    if (type instanceof DefaultEditableFeatureType) {
2295
                        if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
2296
                            return false;
2297
                        }
2298
                    }
2299
                }
2300
                return true;
2301
        }
2302
    }
2303

    
2304
    @Override
2305
    public void beginEditingGroup(String description)
2306
            throws NeedEditingModeException {
2307
        checkInEditingMode();
2308
        commands.startComplex(description);
2309
    }
2310

    
2311
    @Override
2312
    public void endEditingGroup() throws NeedEditingModeException {
2313
        checkInEditingMode();
2314
        commands.endComplex();
2315
    }
2316

    
2317
    @Override
2318
    public boolean isAppendModeSupported() {
2319
        return this.provider.supportsAppendMode();
2320
    }
2321

    
2322
    @Override
2323
    public void export(DataServerExplorer explorer, String provider,
2324
            NewFeatureStoreParameters params, String name) throws DataException {
2325

    
2326
        if (this.getFeatureTypes().size() != 1) {
2327
            throw new NotYetImplemented(
2328
                    "export whith more than one type not yet implemented");
2329
        }
2330
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2331
        FeatureStore target = null;
2332
        FeatureSet features = null;
2333
        DisposableIterator iterator = null;
2334
        try {
2335
            FeatureType type = this.getDefaultFeatureType();
2336
            if ((params.getDefaultFeatureType() == null)
2337
                    || (params.getDefaultFeatureType().size() == 0)) {
2338
                params.setDefaultFeatureType(type.getEditable());
2339

    
2340
            }
2341
            explorer.add(provider, params, true);
2342
            DataManager manager = DALLocator.getDataManager();
2343

    
2344
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2345
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2346

    
2347
            target = (FeatureStore) manager.openStore(provider, openParams);
2348
            FeatureType targetType = target.getDefaultFeatureType();
2349

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

    
2381
    @Override
2382
    public void copyTo(final FeatureStore target) {
2383
        LocalTransaction trans = new LocalTransaction(this.getDataManager(), this.getTransaction(), ((DefaultFeatureStore)target).getTransaction());
2384
        boolean finishEditingAtEnd = false;
2385
        try {
2386
            trans.begin();
2387
            trans.add(this); //Es posible que hubiera que pasarle un local a true
2388
            trans.add(target); //Es posible que hubiera que pasarle un local a true
2389
            if (!target.isEditing() && !target.isAppending()) {
2390
                finishEditingAtEnd = true;
2391
                target.edit(MODE_APPEND);
2392
            }
2393
            this.accept((Object obj) -> {
2394
                Feature f_src = (Feature) obj;
2395
                EditableFeature f_dst = target.createNewFeature(f_src);
2396
                target.insert(f_dst);
2397
            });
2398
            if (finishEditingAtEnd) {
2399
                target.finishEditing();
2400
            }
2401
            trans.commit();
2402

    
2403
        } catch (Exception ex) {
2404
            try {
2405
                if (finishEditingAtEnd) {
2406
                    target.cancelEditing();
2407
                }
2408
            } catch (Exception ex1) {
2409
            }
2410
            trans.abortQuietly();
2411
            throw new RuntimeException("Can't copy store.", ex);
2412
        } finally {
2413
            trans.closeQuietly();
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
        addRequiredAttributes(featureQuery);
2473
        return new DefaultFeatureSet(this, featureQuery);
2474
    }
2475

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2710
            private final FeatureStore store;
2711
            private final FeatureQuery query;
2712
            private final Observer observer;
2713

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2870
        }
2871

    
2872
        return type;
2873
    }
2874

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

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

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

    
2900
    @Override
2901
    public FeatureType getDefaultFeatureType() throws DataException {
2902
        try {
2903

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

    
2916
            return avoidEditable(defaultFeatureType);
2917

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

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

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

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

    
2971
    public FeatureType getProviderDefaultFeatureType() {
2972
        return defaultFeatureType;
2973
    }
2974

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

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

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

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

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

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

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

    
3053
    }
3054

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

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

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

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

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

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

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

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

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

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

    
3131
        return createIndex(indexTypeName, featureType, attributeName,
3132
                indexName, false, null);
3133
    }
3134

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

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

    
3148
        return createIndex(indexTypeName, featureType, attributeName,
3149
                indexName, true, observer);
3150
    }
3151

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

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

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

    
3168
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
3169
        return index;
3170
    }
3171

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

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

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

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

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

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

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

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

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

    
3299
    @Override
3300
    public DataQuery createQuery() {
3301
        return createFeatureQuery();
3302
    }
3303

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3427
    }
3428

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

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

    
3449
    public FeatureTypeManager getFeatureTypeManager() {
3450
        return this.featureTypeManager;
3451
    }
3452

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

    
3474
    private Long getTemporalOID() {
3475
        return this.temporalOid++;
3476
    }
3477

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

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

    
3499
    @Override
3500
    public DataStore getStore() {
3501
        return this;
3502
    }
3503

    
3504
    @Override
3505
    public FeatureStore getFeatureStore() {
3506
        return this;
3507
    }
3508

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

    
3519
        featureCount = null;
3520
    }
3521

    
3522
    @Override
3523
    public FeatureCache getCache() {
3524
        return cache;
3525
    }
3526

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

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

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

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

    
3581
    }
3582

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

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

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

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

    
3620
    @Override
3621
    public Collection getTimes() {
3622
        if (this.timeSupport != null) {
3623
            return this.timeSupport.getTimes();
3624
        }
3625
        return this.provider.getTimes();
3626
    }
3627

    
3628
    @Override
3629
    public Collection getTimes(Interval interval) {
3630
        if (this.timeSupport != null) {
3631
            return this.timeSupport.getTimes(interval);
3632
        }
3633
        return this.provider.getTimes(interval);
3634
    }
3635

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

    
3665
        this.timeSupport = timeSupport;
3666
    }
3667

    
3668
    @Override
3669
    @SuppressWarnings("CloneDoesntCallSuperClone")
3670
    public Object clone() throws CloneNotSupportedException {
3671

    
3672
        DataStoreParameters dsp = getParameters();
3673

    
3674
        DefaultFeatureStore cloned_store = null;
3675

    
3676
        try {
3677
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3678
                    openStore(this.getProviderName(), dsp);
3679
            if (transforms != null) {
3680
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3681
                cloned_store.transforms.setStoreForClone(cloned_store);
3682
            }
3683
        } catch (Exception e) {
3684
            throw new CloneException(e);
3685
        }
3686
        return cloned_store;
3687

    
3688
    }
3689

    
3690
    @Override
3691
    public Feature getFeature(DynObject dynobject) {
3692
        if (dynobject instanceof DynObjectFeatureFacade) {
3693
            Feature f = ((DynObjectFeatureFacade) dynobject).getFeature();
3694
            return f;
3695
        }
3696
        return null;
3697
    }
3698

    
3699
    @Override
3700
    public Iterator iterator() {
3701
        FeatureSet fset = null;
3702
        try {
3703
            fset = this.getFeatureSet();
3704
            return fset.fastIterator();
3705
        } catch (DataException ex) {
3706
            throw new RuntimeException(ex);
3707
        } finally {
3708
            DisposeUtils.disposeQuietly(fset);
3709
        }
3710
    }
3711

    
3712
    @Override
3713
    public long size64() {
3714
        FeatureSet fset = null;
3715
        try {
3716
            fset = this.getFeatureSet();
3717
            return fset.getSize();
3718
        } catch (DataException ex) {
3719
            throw new RuntimeException(ex);
3720
        } finally {
3721
            DisposeUtils.disposeQuietly(fset);
3722
        }
3723
    }
3724

    
3725
    @Override
3726
    public ExpressionBuilder createExpressionBuilder() {
3727
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3728
        return builder;
3729
    }
3730

    
3731
    @Override
3732
    public ExpressionBuilder createExpression() {
3733
        return createExpressionBuilder();
3734
    }
3735

    
3736
    public FeatureSet features() throws DataException {
3737
        // This is to avoid jython to create a property with this name
3738
        // to access method getFeatures.
3739
        return this.getFeatureSet();
3740
    }
3741

    
3742
    @Override
3743
    public DataStoreProviderFactory getProviderFactory() {
3744
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3745
        return factory;
3746
    }
3747

    
3748
    @Override
3749
    public void useCache(String providerName, DynObject parameters) throws DataException {
3750
        throw new UnsupportedOperationException();
3751
    }
3752

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

    
3758
    @Override
3759
    public Throwable getBreakingsCause() {
3760
        return this.state.getBreakingsCause();
3761
    }
3762

    
3763
    @Override
3764
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3765
        FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3766
        if (!factory.supportNumericOID()) {
3767
            return null;
3768
        }
3769
        SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3770
        return wrappedIndex;
3771
    }
3772

    
3773
    @Override
3774
    public FeatureReference getFeatureReference(String code) {
3775
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3776
        return featureReference;
3777
    }
3778

    
3779
    @Override
3780
    public long getPendingChangesCount() {
3781
        if (this.featureManager == null) {
3782
            return 0;
3783
        }
3784
        return this.featureManager.getPendingChangesCount();
3785
    }
3786

    
3787
    private ResourcesStorage resourcesStorage;
3788

    
3789
    @Override
3790
    public ResourcesStorage getResourcesStorage() {
3791
        if (this.resourcesStorage != null) {
3792
            if(this.resourcesStorage instanceof SupportTransactions){
3793
                if( this.getTransaction()!=null ) {
3794
                    try {
3795
                        this.getTransaction().add(((SupportTransactions)this.resourcesStorage), false);
3796
                    } catch (DataException ex) {
3797
                        LOGGER.warn("Can't get resources storage, don't add to transaction",ex);
3798
                        return null;
3799
                    }
3800
                }
3801
//                ((SupportTransactions)this.resourcesStorage).setTransaction(this.getTransaction());
3802
            }
3803
            DisposeUtils.bind(this.resourcesStorage);
3804
            return this.resourcesStorage;
3805
        }
3806
        ResourcesStorage theResourcesStorage;
3807
        try {
3808
            theResourcesStorage = this.provider.getResourcesStorage();
3809
            if (theResourcesStorage != null) {
3810
                this.resourcesStorage = theResourcesStorage;
3811
                DisposeUtils.bind(this.resourcesStorage);
3812
                return theResourcesStorage;
3813
            }
3814
        } catch (Throwable th) {
3815

    
3816
        }
3817
        try {
3818
            DataServerExplorer explorer = this.getExplorer();
3819
            if (explorer == null) {
3820
                return null;
3821
            }
3822
            theResourcesStorage = explorer.getResourcesStorage(this);
3823
            explorer.dispose();
3824
            this.resourcesStorage = theResourcesStorage;
3825
            DisposeUtils.bind(this.resourcesStorage);
3826
            return theResourcesStorage;
3827
        } catch (Exception ex) {
3828
            LOGGER.trace("Can't create resources storage", ex);
3829
            return null;
3830
        }
3831
    }
3832

    
3833
    @Override
3834
    public StoresRepository getStoresRepository() {
3835
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3836
        StoresRepository localRepository = this.provider.getStoresRepository();
3837
        if (localRepository == null) {
3838
            return mainRepository;
3839
        }
3840
        StoresRepository repository = new BaseStoresRepository(this.getName());
3841
        repository.addRepository(localRepository);
3842
        repository.addRepository(mainRepository);
3843
        return repository;
3844
    }
3845

    
3846
    @Override
3847
    public Feature getSampleFeature() {
3848
        if( sampleFeatureCache==null )  {
3849
            this.sampleFeatureCache = new CachedValue<Feature>(sample_feature_cache_timeout_ms) {
3850
                @Override
3851
                protected void reload() {
3852
                    Feature sampleFeature;
3853
                    long t1 = System.currentTimeMillis();
3854
                    try {                        
3855
                        FeatureSelection theSelection = getFeatureSelection();
3856
                        if (theSelection != null && !theSelection.isEmpty()) {
3857
                            sampleFeature = theSelection.first();
3858
                        } else {
3859
                            sampleFeature = first();
3860
                        }
3861
                        if (sampleFeature == null) {
3862
                            sampleFeature = createNewFeature();
3863
                        }
3864
                    } catch (Exception ex) {
3865
                        sampleFeature = null;
3866
                    }
3867
                    long t2 = System.currentTimeMillis();
3868
                    if( (t2 - t1)>5000 ) {
3869
                        // Mas de 5 seg es muy costoso, subimos mucho el tiempo de cache.
3870
                        this.setExpireTime(((60*60)*2)*1000); // 2h
3871
                    }
3872
                    this.setValue(sampleFeature);
3873
                }
3874
            };
3875
        }
3876
        return this.sampleFeatureCache.get();
3877
    }
3878

    
3879
    @Override
3880
    public boolean supportReferences() {
3881
        try {
3882
            return this.getDefaultFeatureType().supportReferences();
3883
        } catch (Exception ex) {
3884
            return false;
3885
        }
3886
    }
3887

    
3888
    private Boolean temporary = null;
3889
    
3890
    @Override
3891
    public boolean isTemporary() {
3892
        if(temporary != null) {
3893
            return this.temporary;
3894
        }
3895
        if (this.provider == null) {
3896
            return true;
3897
        }
3898
        return this.provider.isTemporary();
3899
    }
3900
    
3901
    @Override
3902
    public void setTemporary(Boolean temporary){
3903
        this.temporary = temporary;
3904
    }
3905

    
3906
    public FeatureType getOriginalFeatureType(FeatureType featureType) {
3907
        // FIXME this don't work for Store.featureTypes.size() > 1
3908
        
3909
        FeatureTypeManager manager = this.featureTypeManager;
3910
        if (manager == null) {
3911
            return null;
3912
        }
3913
        FeatureType originalFeatureType = manager.getOriginalFeatureType();
3914
        if (originalFeatureType == null) {
3915
            return null;
3916
        }
3917
        return originalFeatureType.getCopy();
3918
    }
3919

    
3920
    @Override
3921
    public Object getProperty(String name) {
3922
        if (this.propertiesSupportHelper == null) {
3923
            return null;
3924
        }
3925
        return this.propertiesSupportHelper.getProperty(name);
3926
    }
3927

    
3928
    @Override
3929
    public void setProperty(String name, Object value) {
3930
        if (this.propertiesSupportHelper == null) {
3931
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3932
        }
3933
        this.propertiesSupportHelper.setProperty(name, value);
3934
    }
3935

    
3936
    @Override
3937
    public Map<String, Object> getProperties() {
3938
        if (this.propertiesSupportHelper == null) {
3939
            return Collections.EMPTY_MAP;
3940
        }
3941
        return this.propertiesSupportHelper.getProperties();
3942
    }
3943

    
3944
    @Override
3945
    public Feature getOriginalFeature(FeatureReference id) {
3946
        if (this.featureManager == null) {
3947
            return null;
3948
        }
3949
        return featureManager.getOriginal(id);
3950
    }
3951

    
3952
    @Override
3953
    public Feature getOriginalFeature(Feature feature) {
3954
        if (feature == null) {
3955
            return null;
3956
        }
3957
        return getOriginalFeature(feature.getReference());
3958
    }
3959

    
3960
    @Override
3961
    public boolean isFeatureModified(FeatureReference id) {
3962
        if (this.featureManager == null) {
3963
            return false;
3964
        }
3965
        return featureManager.isFeatureModified(id);
3966
    }
3967

    
3968
    @Override
3969
    public boolean isFeatureModified(Feature feature) {
3970
        if (feature == null) {
3971
            return false;
3972
        }
3973
        return isFeatureModified(feature.getReference());
3974
    }
3975
    
3976

    
3977
    @Override
3978
    public void setTransaction(DataTransaction transaction) {
3979
        DataTransaction prevTransaction = transactionHelper.getTransaction();
3980
        if( prevTransaction!=null ) {
3981
            prevTransaction.deleteObserver(transactionObserver);
3982
        }
3983
        this.transactionHelper.setTransaction(transaction);
3984
        if (this.provider != null){
3985
            if (transaction == null || transaction instanceof DataTransactionServices) {
3986
                this.provider.setTransaction((DataTransactionServices) transaction);
3987
            }
3988
        }
3989
        if( transaction!=null ) {
3990
            transaction.addObserver(transactionObserver);
3991
        }
3992
    }
3993

    
3994
    @Override
3995
    public DataTransaction getTransaction() {
3996
        DataTransaction xtransaction = transactionHelper.getTransaction();
3997
        return xtransaction;
3998
    }
3999

    
4000
    @Override
4001
    public String toString() {
4002
        try {
4003
            ToStringBuilder builder = new ToStringBuilder(this);
4004
            builder.append("provider", this.provider==null? null:this.provider.getProviderName());
4005
            builder.append("fullname", this.getFullName());
4006
            return builder.toString();
4007
        } catch (Exception e) {
4008
            return super.toString();
4009
        }
4010
    }
4011

    
4012
    public String createUniqueID() {
4013
        UUID x = UUID.randomUUID();
4014
        String s = x.toString();
4015
        return s;
4016
    }
4017

    
4018
    @Override
4019
    public List<FeatureReference> getEditedFeatures() {
4020
        if( this.featureManager == null ) {
4021
            return Collections.EMPTY_LIST;
4022
        }
4023
        List<FeatureReference> references = this.featureManager.getAddedAndUpdatedFeatures();
4024
        if( references==null ) {
4025
            return Collections.EMPTY_LIST;
4026
        }
4027
        return references;
4028
    }
4029
    
4030
    @Override
4031
    public List<FeatureReference> getEditedFeaturesNotValidated() {
4032

    
4033
        try {
4034
            if (this.featureManager == null) {
4035
                return Collections.EMPTY_LIST;
4036
            }
4037
            
4038
            FeatureType type = this.getDefaultFeatureTypeQuietly();
4039
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
4040
            
4041
//            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS | CHECK_BASIC : 0;
4042
            int checks = CHECK_REQUIREDS | CHECK_BASIC;
4043
            if(type.isCheckFeaturesAtFinishEditing()){
4044
                checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
4045
            }
4046
            if (checks == 0) {
4047
                return Collections.EMPTY_LIST;
4048
            }
4049
            List<FeatureReference> references = this.featureManager
4050
                    .getAddedAndUpdatedFeaturesNotValidated(rules, checks);
4051
            if (references == null) {
4052
                return Collections.EMPTY_LIST;
4053
            }
4054
            return references;
4055
        } catch (DataException ex) {
4056
            return null;
4057
        }
4058

    
4059
    }
4060

    
4061
    @Override
4062
    public Iterator<Feature> getFeaturesIterator(Iterator<FeatureReference> references) {
4063
        return new FeatureReferenceIteratorToFeatureIterator(this, references);
4064
    }
4065

    
4066
    @Override
4067
    public Iterable<Feature> getFeaturesIterable(Iterator<FeatureReference> references) {
4068
        return () -> new FeatureReferenceIteratorToFeatureIterator(this, references);
4069
    }
4070

    
4071
    @Override
4072
    public boolean isFeatureSelectionAvailable() {
4073
        try {
4074
            FeatureType type = this.getDefaultFeatureType();
4075
            return type.supportReferences();
4076
        } catch (DataException ex) {
4077
            return false;
4078
        }
4079
    }
4080
    
4081
    @Override
4082
    public boolean canBeEdited() {
4083
        return this.transforms.isEmpty();
4084
    }
4085

    
4086
    @Override
4087
    public String getLabel() {
4088
        FeatureType ft = this.getDefaultFeatureTypeQuietly();
4089
        if( ft == null ) {
4090
            return this.getName();
4091
        }
4092
        String label = ft.getLabel();
4093
        if( StringUtils.isBlank(label) ) {
4094
            return this.getName();
4095
        }
4096
        return label;
4097
    }
4098

    
4099
    public void addRequiredAttributes(FeatureQuery fq) {
4100
        if(this.transforms != null && !this.transforms.isEmpty()){
4101
            //FIXME: A?adir solo los atributos necesarios para la transformaci?n
4102
            // this.transforms.addRequiredAttributes(fq) //No hay api todav?a
4103
            fq.retrievesAllAttributes();
4104
        }
4105
    }
4106

    
4107
    
4108
}