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

History | View | Annotate | Download (146 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.exception.CloneException;
67
import org.gvsig.fmap.dal.exception.CloseException;
68
import org.gvsig.fmap.dal.exception.CreateException;
69
import org.gvsig.fmap.dal.exception.DataException;
70
import org.gvsig.fmap.dal.exception.DataRuntimeException;
71
import org.gvsig.fmap.dal.exception.InitializeException;
72
import org.gvsig.fmap.dal.exception.OpenException;
73
import org.gvsig.fmap.dal.exception.ReadException;
74
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
75
import org.gvsig.fmap.dal.exception.WriteException;
76
import org.gvsig.fmap.dal.feature.DisposableFeatureSetIterable;
77
import org.gvsig.fmap.dal.feature.EditableFeature;
78
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
79
import org.gvsig.fmap.dal.feature.EditableFeatureType;
80
import org.gvsig.fmap.dal.feature.Feature;
81
import static org.gvsig.fmap.dal.feature.Feature.CHECK_BASIC;
82
import static org.gvsig.fmap.dal.feature.Feature.CHECK_REQUIREDS;
83
import static org.gvsig.fmap.dal.feature.Feature.CHECK_RULES_AT_EDITING;
84
import static org.gvsig.fmap.dal.feature.Feature.CHECK_RULES_AT_FINISH;
85
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
86
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
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.CompoundResourcesStorage;
186
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
187
import org.gvsig.tools.undo.RedoException;
188
import org.gvsig.tools.undo.UndoException;
189
import org.gvsig.tools.undo.command.Command;
190
import org.gvsig.tools.util.CachedValue;
191
import org.gvsig.tools.util.ChainedIterator;
192
import org.gvsig.tools.util.GetItemWithSizeIsEmptyAndIterator64;
193
import org.gvsig.tools.util.HasAFile;
194
import org.gvsig.tools.util.PropertiesSupportHelper;
195
import org.gvsig.tools.util.UnmodifiableBasicMap;
196
import org.gvsig.tools.visitor.VisitCanceledException;
197
import org.gvsig.tools.visitor.Visitor;
198

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

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

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

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

    
215
    private FeatureCommandsStack commands;
216

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

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

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

    
233
    private DefaultDataManager dataManager = null;
234

    
235
    private FeatureStoreProvider provider = null;
236

    
237
    private DefaultFeatureIndexes indexes;
238

    
239
    private DefaultFeatureStoreTransforms transforms;
240

    
241
    /*friend*/ DelegatedDynObject metadata;
242

    
243
    private Set metadataChildren;
244

    
245
    private Long featureCount = null;
246

    
247
    private long temporalOid = 0;
248

    
249
    private FeatureCacheProvider cache;
250

    
251
    private final StateInformation state;
252

    
253
    private FeatureStoreTimeSupport timeSupport;
254

    
255
    private PropertiesSupportHelper propertiesSupportHelper;
256
    private DataTransaction transaction;
257

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

    
266
    private class StateInformation extends HashMap<Object, Object> {
267

    
268
        private static final long serialVersionUID = 4109026189635185666L;
269

    
270
        private boolean broken;
271
        private Throwable breakingsCause;
272

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

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

    
285
        public boolean isBroken() {
286
            return this.broken;
287
        }
288

    
289
        public void broken() {
290
            this.broken = true;
291
        }
292

    
293
        public Throwable getBreakingsCause() {
294
            return this.breakingsCause;
295
        }
296

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

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

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

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

    
335
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
336

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

    
342
        this.dataManager = (DefaultDataManager) dataManager;
343

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

    
352
    }
353

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

    
363
            // Habria que crear un metodo en el proveedor para que de prioidad
364
            // a los parametros frente a lo que se a leido en el fichero dal
365
            // DataStoreProvider arreglalo segun los parametros del usuario
366
            // fixFeatureTypeFromParameters
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
        if( this.transaction!=null ) {
526
            this.transaction.remove(this);
527
            this.transaction = null;
528
        }
529
    }
530

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

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

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

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

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

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

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

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

    
689
        }
690

    
691
        if (evaluatedAttr.isEmpty()) {
692
            evaluatedAttr = null;
693
        }
694

    
695
        state.set("evaluatedAttributes", evaluatedAttr);
696
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
697

    
698
    }
699

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

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

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

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

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

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

    
812
                }
813

    
814
            }
815
        } catch (Throwable th) {
816
            state.setBreakingsCause(th);
817
        }
818

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

    
823
            if (defaultFeatureType == null
824
                    || defaultFeatureType.getId() == null
825
                    || !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
826

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

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

    
851
    public DataStoreProviderServices getStoreProviderServices() {
852
        return this;
853
    }
854

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

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

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

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

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

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

    
903
            definition.addDynFieldString("defaultFeatureTypeId")
904
                    .setMandatory(true).setPersistent(true);
905
        }
906
    }
907

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

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

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

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

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

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

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

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

    
999
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1000
    }
1001

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

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

    
1026
    }
1027

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1208
    }
1209

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

    
1215
    @Override
1216
    public void beginComplexNotification() {
1217
        this.delegateObservable.beginComplexNotification();
1218

    
1219
    }
1220

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

    
1225
    }
1226

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

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

    
1241
    @Override
1242
    public void deleteObservers() {
1243
        this.delegateObservable.deleteObservers();
1244

    
1245
    }
1246

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

    
1265
        } else if (observable instanceof FeatureStoreProvider) {
1266
            if (observable == this.provider) {
1267

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

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

    
1284
    private long currentVersionOfUpdate() {
1285
        return this.versionOfUpdate;
1286
    }
1287

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

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

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

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

    
1320
        if (featureTypeManager != null) {
1321
            DisposeUtils.disposeQuietly(featureTypeManager);
1322
            featureTypeManager = null;
1323

    
1324
        }
1325

    
1326
        // TODO implementar un dispose para estos dos
1327
        featureManager = null;
1328
        if (spatialManager != null) {
1329
            spatialManager.clear();
1330
        }
1331
        spatialManager = null;
1332

    
1333
        featureCount = null;
1334

    
1335
        this.lastMode = this.mode;
1336
        mode = MODE_QUERY;
1337
        hasStrongChanges = true; // Lo deja a true por si las moscas
1338

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

    
1350
    @Override
1351
    synchronized public void edit() throws DataException {
1352
        edit(MODE_FULLEDIT);
1353
    }
1354

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

    
1374
                case MODE_FULLEDIT:
1375
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1376
                            newSessionCode, mode).isCanceled()) {
1377
                        return;
1378
                    }
1379
                    this.editingSessionCode = newSessionCode;
1380
                    invalidateIndexes();
1381
                    featureManager = new FeatureManager(this);
1382
                    featureTypeManager = new FeatureTypeManager(this);
1383
                    spatialManager = new SpatialManager(this);
1384

    
1385
                    commands = new DefaultFeatureCommandsStack(
1386
                            this, featureManager,
1387
                            spatialManager, featureTypeManager);
1388
                    this.mode = MODE_FULLEDIT;
1389
                    hasStrongChanges = false;
1390
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING, newSessionCode, this.mode);
1391
                    break;
1392

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

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

    
1435
    private void invalidateIndexes() {
1436
        setIndexesValidStatus(false);
1437
    }
1438

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

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

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

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

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

    
1500
    @Override
1501
    public boolean isAppending() {
1502
        return mode == MODE_APPEND;
1503
    }
1504

    
1505
    @Override
1506
    synchronized public void update(EditableFeatureType type)
1507
            throws DataException {
1508
        try {
1509
            if (type == null) {
1510
                throw new NullFeatureTypeException(getName());
1511
            }
1512

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

    
1536
                    break;
1537
                case MODE_FULLEDIT:
1538
                    if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1539
                        return;
1540
                    }
1541
                    newVersionOfUpdate();
1542

    
1543
                    FeatureType oldt = type.getSource().getCopy();
1544
                    FeatureType newt = type.getCopy();
1545
                    commands.update(newt, oldt);
1546
                    hasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1547
                    notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1548
                    break;
1549
                case MODE_APPEND:
1550
                case MODE_PASS_THROUGH:
1551
                    throw new NeedEditingModeException(this.getName());
1552

    
1553
            }
1554
        } catch (Exception e) {
1555
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1556
        }
1557
    }
1558

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

    
1574
        }
1575
    }
1576

    
1577
    @Override
1578
    public void delete(String filter) {
1579
        if (StringUtils.isBlank(filter)) {
1580
            return;
1581
        }
1582
        this.delete(ExpressionUtils.createExpression(filter));
1583
    }
1584

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

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

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

    
1646
            //Update the featureManager and the spatialManager
1647
            featureManager.delete(feature);
1648
            spatialManager.deleteFeature(feature);
1649

    
1650
            newVersionOfUpdate();
1651
            hasStrongChanges = true;
1652
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1653
        } catch (Exception e) {
1654
            throw new StoreDeleteFeatureException(e, this.getName());
1655
        }
1656
    }
1657

    
1658
    @Override
1659
    public synchronized void insert(FeatureSet set) throws DataException {
1660
        switch (mode) {
1661
            case MODE_QUERY:
1662
                throw new NeedEditingModeException(this.getName());
1663

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

    
1679
    private static EditableFeature lastChangedFeature = null;
1680

    
1681
    @Override
1682
    public synchronized void insert(EditableFeature feature)
1683
            throws DataException {
1684
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1685
        try {
1686
            switch (mode) {
1687
                case MODE_QUERY:
1688
                    throw new NeedEditingModeException(this.getName());
1689

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

    
1705
                case MODE_FULLEDIT:
1706
                    if (feature.isUpdatable()) {
1707
                        throw new NoNewFeatureInsertException(this.getName());
1708
                    }
1709
                    feature.validate(CHECK_RULES_AT_EDITING);
1710
                    commands.insert(feature);
1711
                    break;
1712

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

    
1731
    synchronized public void doInsert(EditableFeature feature)
1732
            throws DataException {
1733
        checkIsOwnFeature(feature);
1734

    
1735
        waitForIndexes();
1736

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

    
1751
        featureManager.add(feature);
1752
        spatialManager.insertFeature(newFeature);
1753

    
1754
        hasStrongChanges = true;
1755
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1756
    }
1757

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

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

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

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

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

    
1864
            //Update the featureManager and the spatialManager
1865
            Feature newf = feature.getNotEditableCopy();
1866
            featureManager.update(feature, oldFeature);
1867
            spatialManager.updateFeature(newf, oldFeature);
1868

    
1869
            hasStrongChanges = true;
1870
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1871
        } catch (Exception e) {
1872
            throw new StoreUpdateFeatureException(e, this.getName());
1873
        }
1874
    }
1875

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

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

    
1910
    @Override
1911
    public List getRedoInfos() {
1912
        if (isEditing() && (commands != null)) {
1913
            return commands.getRedoInfos();
1914
        } else {
1915
            return null;
1916
        }
1917
    }
1918

    
1919
    @Override
1920
    public List getUndoInfos() {
1921
        if (isEditing() && (commands != null)) {
1922
            return commands.getUndoInfos();
1923
        } else {
1924
            return null;
1925
        }
1926
    }
1927

    
1928
    public synchronized FeatureCommandsStack getCommandsStack()
1929
            throws DataException {
1930
        checkInEditingMode();
1931
        return commands;
1932
    }
1933

    
1934
    @Override
1935
    public boolean cancelEditingQuietly() {
1936
        try {
1937
            this.cancelEditing();
1938
            return true;
1939
        } catch (Exception ex) {
1940
            LOGGER.debug("Can't cancel editing", ex);
1941
            return false;
1942
        }
1943
    }
1944

    
1945
    @Override
1946
    synchronized public void cancelEditing() throws DataException {
1947
        try {
1948
            switch (mode) {
1949
                case MODE_QUERY:
1950
                    throw new NeedEditingModeException(this.getName());
1951

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

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

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

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

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

    
2016
                case MODE_APPEND:
2017
                    if (selection != null) {
2018
                        selection = null;
2019
                    }
2020
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2021
                        return;
2022
                    }
2023
                    trans.begin();
2024
                    trans.add(this);
2025
                    saveDALFile();
2026
                    provider.endAppend();
2027
                    exitEditingMode();
2028
                    this.updateComputedFields(computedFields);
2029
                    loadDALFile();
2030
                    updateIndexes();
2031
                    trans.commit();
2032
                    trans.close();
2033
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2034
                    break;
2035

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

    
2069
                        }
2070
                        this.updateComputedFields(computedFields);
2071
                        exitEditingMode();
2072
                        loadDALFile();
2073
                        updateIndexes();
2074
                        trans.commit();
2075
                        trans.close();
2076
                    } else {
2077
                        exitEditingMode();
2078
                    }
2079
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2080
                    break;
2081
                case MODE_PASS_THROUGH:
2082
                    if (selection != null) {
2083
                        selection = null;
2084
                    }
2085
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2086
                        return;
2087
                    }
2088
                    exitEditingMode();
2089
                    updateIndexes();
2090
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2091
                    break;
2092
            }
2093
        } catch (ValidateFeaturesException | WriteNotAllowedException ex) {
2094
            // Don't notify failed.
2095
            trans.abortQuietly();
2096
            throw ex;
2097
        } catch (PerformEditingException pee) {
2098
            trans.abortQuietly();
2099
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2100
            throw new WriteException(provider.getSourceId().toString(), pee);
2101
        } catch (Exception e) {
2102
            trans.abortQuietly();
2103
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2104
            throw new FinishEditingException(e);
2105
        } finally {
2106
            trans.closeQuietly();
2107
        }
2108
    }
2109
    
2110
    @Override
2111
    public String getEditingSession() {
2112
        return this.editingSessionCode;
2113
    }
2114

    
2115
    private Map<String, List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
2116
        Map<String, List<FeatureAttributeDescriptor>> r = new HashMap<>();
2117

    
2118
        List<FeatureType> theTypes = new ArrayList<>();
2119
        theTypes.addAll(this.getFeatureTypes());
2120
        theTypes.add(this.getDefaultFeatureType());
2121
        for (int n = 0; n < theTypes.size(); n++) {
2122
            FeatureType type = theTypes.get(n);
2123
            for (FeatureAttributeDescriptor attrdesc : type) {
2124
                FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
2125
                if (emulator != null) {
2126
                    List<FeatureAttributeDescriptor> l = r.get(type.getId());
2127
                    if (l == null) {
2128
                        l = new ArrayList<>();
2129
                        r.put(type.getId(), l);
2130
                    }
2131
                    l.add(attrdesc);
2132
                }
2133
            }
2134
        }
2135
        return r;
2136
    }
2137

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

    
2140
        List<FeatureType> theTypes = new ArrayList<>();
2141
        theTypes.addAll(this.getFeatureTypes());
2142
        theTypes.add(this.getDefaultFeatureType());
2143
        for (int n = 0; n < theTypes.size(); n++) {
2144
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
2145
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
2146
            if (x != null && !x.isEmpty()) {
2147
                for (FeatureAttributeDescriptor attrdesc : x) {
2148
                    if (type.get(attrdesc.getName()) == null) {
2149
                        type.add(attrdesc);
2150
                    }
2151
                }
2152
            }
2153
        }
2154

    
2155
    }
2156

    
2157
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
2158
        // FIXME: Falta por implementar
2159
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
2160
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
2161
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
2162
//                if (attributeDescriptor.isComputed()) {
2163
//                    target.remove(attributeDescriptor.getName());
2164
//                }
2165
//            }
2166
//        }
2167
        return ftypes;
2168
    }
2169

    
2170
    private void clearResourcesCache() {
2171
        ResourcesStorage theResourcesStorage = null;
2172
        try {
2173
            theResourcesStorage = this.getResourcesStorage();
2174
            if (theResourcesStorage == null ) {
2175
                return;
2176
            }
2177
            theResourcesStorage.clearCache();
2178
        } catch (Throwable ex) {
2179
            LOGGER.warn("Can't clear resources for store '"+this.getFullNameForTraces()+"'.", ex);
2180
        } finally {
2181
            DisposeUtils.disposeQuietly(theResourcesStorage);
2182
        }
2183
    }
2184
    
2185
    private void saveDALFile() {
2186
        if( this.ignoreDALResource ) {
2187
            return;
2188
        }
2189
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2190
        ResourcesStorage theResourcesStorage = null;
2191
        try {
2192
            theResourcesStorage = this.getResourcesStorage();
2193
            if (theResourcesStorage == null || theResourcesStorage.isReadOnly()) {
2194
                return;
2195
            }
2196
            resource = theResourcesStorage.getResource("dal");
2197
            if (resource == null || resource.isReadOnly()) {
2198
                return;
2199
            }
2200
            DALFile dalFile = DALFile.getDALFile();
2201
            dalFile.setStore(this);
2202
            if (!dalFile.isEmpty()) {
2203
                dalFile.write(resource);
2204
            }
2205
        } catch (Throwable ex) {
2206
            LOGGER.warn("Can't save DAL resource", ex);
2207
        } finally {
2208
            IOUtils.closeQuietly(resource);
2209
            DisposeUtils.disposeQuietly(theResourcesStorage);
2210
        }
2211
    }
2212

    
2213
    private void loadDALFile() {
2214
        if( this.ignoreDALResource ) {
2215
            return;
2216
        }
2217
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2218
        ResourcesStorage theResourcesStorage = null;
2219
        try {
2220
            theResourcesStorage = this.getResourcesStorage();
2221
            if (theResourcesStorage == null) {
2222
                return;
2223
            }
2224
            resource = theResourcesStorage.getResource("dal");
2225
            if (resource == null || !resource.exists()) {
2226
                return;
2227
            }
2228
            DALFile dalFile = DALFile.getDALFile(resource);
2229
            if (!dalFile.isEmpty()) {
2230
                dalFile.updateStore(this);
2231
            }
2232
        } catch (Throwable ex) {
2233
            if (resource == null || theResourcesStorage == null) {
2234
                if (theResourcesStorage == null) {
2235
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=null)", ex);
2236
                } else {
2237
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2238
                }
2239
            } else {
2240
                LOGGER.warn("Can't load DAL resource (resname=" + resource.getName() + ", resurl=" + Objects.toString(resource.getURL()) + ", storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2241
            }
2242
        } finally {
2243
            IOUtils.closeQuietly(resource);
2244
            DisposeUtils.disposeQuietly(theResourcesStorage);
2245
        }
2246
    }
2247

    
2248
    /**
2249
     * Save changes in the provider without leaving the edit mode. Do not call
2250
     * observers to communicate a change of ediding mode. The operation's
2251
     * history is eliminated to prevent inconsistencies in the data.
2252
     *
2253
     * @throws DataException
2254
     */
2255
    @Override
2256
    synchronized public void commitChanges() throws DataException {
2257
        LOGGER.debug("commitChanges of mode: {}", mode);
2258
        if (!canCommitChanges()) {
2259
            throw new WriteNotAllowedException(getName());
2260
        }
2261
        try {
2262
            switch (mode) {
2263
                case MODE_QUERY:
2264
                    throw new NeedEditingModeException(this.getName());
2265

    
2266
                case MODE_APPEND:
2267
                    this.provider.endAppend();
2268
                    exitEditingMode();
2269
                    invalidateIndexes();
2270
                    this.provider.beginAppend();
2271
                    break;
2272

    
2273
                case MODE_FULLEDIT:
2274
                    if (hasStrongChanges && !this.allowWrite()) {
2275
                        throw new WriteNotAllowedException(getName());
2276
                    }
2277
                    // FIXME: OOhh!!!! no se disparan eventos, VCSGis no se entera de estos cambios.
2278
                    if (hasStrongChanges) {
2279
                        validateFeaturesAtFinishEditing();
2280
                        provider.performChanges(featureManager.getDeleted(),
2281
                                featureManager.getInserted(),
2282
                                featureManager.getUpdated(),
2283
                                removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2284
                    }
2285
                    invalidateIndexes();
2286
                    featureManager = new FeatureManager(this);
2287
                    featureTypeManager = new FeatureTypeManager(this);
2288
                    spatialManager = new SpatialManager(this);
2289

    
2290
                    commands
2291
                            = new DefaultFeatureCommandsStack(this, featureManager,
2292
                                    spatialManager, featureTypeManager);
2293
                    featureCount = null;
2294
                    hasStrongChanges = false;
2295
                    break;
2296
            }
2297
        } catch (Exception e) {
2298
            throw new FinishEditingException(e);
2299
        }
2300
    }
2301

    
2302
    @Override
2303
    synchronized public boolean canCommitChanges() throws DataException {
2304
        if (!this.allowWrite()) {
2305
            return false;
2306
        }
2307
        switch (mode) {
2308
            default:
2309
            case MODE_QUERY:
2310
                return false;
2311

    
2312
            case MODE_APPEND:
2313
                return true;
2314

    
2315
            case MODE_FULLEDIT:
2316
                List types = this.getFeatureTypes();
2317
                for (int i = 0; i < types.size(); i++) {
2318
                    Object type = types.get(i);
2319
                    if (type instanceof DefaultEditableFeatureType) {
2320
                        if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
2321
                            return false;
2322
                        }
2323
                    }
2324
                }
2325
                return true;
2326
        }
2327
    }
2328

    
2329
    @Override
2330
    public void beginEditingGroup(String description)
2331
            throws NeedEditingModeException {
2332
        checkInEditingMode();
2333
        commands.startComplex(description);
2334
    }
2335

    
2336
    @Override
2337
    public void endEditingGroup() throws NeedEditingModeException {
2338
        checkInEditingMode();
2339
        commands.endComplex();
2340
    }
2341

    
2342
    @Override
2343
    public boolean isAppendModeSupported() {
2344
        return this.provider.supportsAppendMode();
2345
    }
2346

    
2347
    @Override
2348
    public void export(DataServerExplorer explorer, String provider,
2349
            NewFeatureStoreParameters params, String name) throws DataException {
2350

    
2351
        if (this.getFeatureTypes().size() != 1) {
2352
            throw new NotYetImplemented(
2353
                    "export whith more than one type not yet implemented");
2354
        }
2355
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2356
        FeatureStore target = null;
2357
        FeatureSet features = null;
2358
        DisposableIterator iterator = null;
2359
        try {
2360
            FeatureType type = this.getDefaultFeatureType();
2361
            if ((params.getDefaultFeatureType() == null)
2362
                    || (params.getDefaultFeatureType().size() == 0)) {
2363
                params.setDefaultFeatureType(type.getEditable());
2364

    
2365
            }
2366
            explorer.add(provider, params, true);
2367
            DataManager manager = DALLocator.getDataManager();
2368

    
2369
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2370
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2371

    
2372
            target = (FeatureStore) manager.openStore(provider, openParams);
2373
            FeatureType targetType = target.getDefaultFeatureType();
2374

    
2375
            target.edit(MODE_APPEND);
2376
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2377
            if (featureSelection.getSize() > 0) {
2378
                features = this.getFeatureSelection();
2379
            } else {
2380
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2381
                    FeatureQuery query = createFeatureQuery();
2382
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2383
                        query.getOrder().add(pkattr.getName(), true);
2384
                    }
2385
                    features = this.getFeatureSet(query);
2386
                } else {
2387
                    features = this.getFeatureSet();
2388
                }
2389
            }
2390
            iterator = features.fastIterator();
2391
            while (iterator.hasNext()) {
2392
                DefaultFeature feature = (DefaultFeature) iterator.next();
2393
                target.insert(target.createNewFeature(targetType, feature));
2394
            }
2395
            target.finishEditing();
2396
            target.dispose();
2397
        } catch (Exception e) {
2398
            throw new DataExportException(e, params.toString());
2399
        } finally {
2400
            dispose(iterator);
2401
            dispose(features);
2402
            dispose(target);
2403
        }
2404
    }
2405

    
2406
    @Override
2407
    public void copyTo(final FeatureStore target) {
2408
        LocalTransaction trans = new LocalTransaction(this.getDataManager(), this.getTransaction(), ((DefaultFeatureStore)target).getTransaction());
2409
        boolean finishEditingAtEnd = false;
2410
        try {
2411
            trans.begin();
2412
            trans.add(this); //Es posible que hubiera que pasarle un local a true
2413
            trans.add(target); //Es posible que hubiera que pasarle un local a true
2414
            if (!target.isEditing() && !target.isAppending()) {
2415
                finishEditingAtEnd = true;
2416
                target.edit(MODE_APPEND);
2417
            }
2418
            this.accept((Object obj) -> {
2419
                Feature f_src = (Feature) obj;
2420
                EditableFeature f_dst = target.createNewFeature(f_src);
2421
                target.insert(f_dst);
2422
            });
2423
            if (finishEditingAtEnd) {
2424
                target.finishEditing();
2425
            }
2426
            trans.commit();
2427

    
2428
        } catch (Exception ex) {
2429
            try {
2430
                if (finishEditingAtEnd) {
2431
                    target.cancelEditing();
2432
                }
2433
            } catch (Exception ex1) {
2434
            }
2435
            trans.abortQuietly();
2436
            throw new RuntimeException("Can't copy store.", ex);
2437
        } finally {
2438
            trans.closeQuietly();
2439
        }
2440

    
2441
    }
2442

    
2443
    //
2444
    // ====================================================================
2445
    // Obtencion de datos
2446
    // getDataCollection, getFeatureCollection
2447
    //
2448
    @Override
2449
    public DataSet getDataSet() throws DataException {
2450
        return this.getFeatureSet((FeatureQuery)null);
2451
    }
2452

    
2453
    @Override
2454
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2455
        return this.getFeatureSet((FeatureQuery)dataQuery);
2456
    }
2457

    
2458
    @Override
2459
    public void getDataSet(Observer observer) throws DataException {
2460
        checkNotInAppendMode();
2461
        this.getFeatureSet(null, observer);
2462
    }
2463

    
2464
    @Override
2465
    public void getDataSet(DataQuery dataQuery, Observer observer)
2466
            throws DataException {
2467
        checkNotInAppendMode();
2468
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2469
    }
2470

    
2471
    @Override
2472
    public FeatureSet getFeatureSet() throws DataException {
2473
        return this.getFeatureSet((FeatureQuery) null);
2474
    }
2475

    
2476
    @Override
2477
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2478
            throws DataException {
2479
        checkNotInAppendMode();
2480
        if (featureQuery == null) {
2481
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2482
        } else if( featureQuery.hasAggregateFunctions() || featureQuery.hasGroupByColumns() ) {
2483
            // Si tenemos datos por persistir en la bbdd (bien por que estamos en modo 
2484
            // append(batchsize) o por que estamos en modo fulledit y hay cambios
2485
            // realizados, las agrupaciones y funciones de agregado, como las gestiona
2486
            // la bbdd, pueden no dar resultados correctos. Asi que no dejamos hacer
2487
            // estas operaciones.
2488
            if( this.mode==MODE_APPEND  ) {
2489
                throw new UnsupportedOperationException("Can't create a set with aggregate functions or group by columns in append mode");
2490
            }
2491
            if( this.mode == MODE_FULLEDIT ) {
2492
                if( this.featureManager==null || this.featureManager.getPendingChangesCount()>0 ) {
2493
                   throw new UnsupportedOperationException("Can't create a set with aggregate functions or group by columns with editing changes");
2494
                }
2495
            }
2496
        }
2497
        addRequiredAttributes(featureQuery);
2498
        return new DefaultFeatureSet(this, featureQuery);
2499
    }
2500

    
2501
    @Override
2502
    public FeatureSet getFeatureSet(String filter) throws DataException {
2503
        return this.getFeatureSet(filter, null, true);
2504
    }
2505

    
2506
    @Override
2507
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2508
        return this.getFeatureSet(filter, sortBy, true);
2509
    }
2510

    
2511
    @Override
2512
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2513
        return this.getFeatureSet(filter, null, true);
2514
    }
2515

    
2516
    @Override
2517
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2518
        return this.getFeatureSet(filter, sortBy, true);
2519
    }
2520

    
2521
    @Override
2522
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2523
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2524
        return this.getFeatureSet(query);
2525
    }
2526

    
2527
    @Override
2528
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2529
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2530
        return this.getFeatureSet(query);
2531
    }
2532

    
2533
    @Override
2534
    public List<Feature> getFeatures(String filter) {
2535
        return this.getFeatures(filter, null, true);
2536
    }
2537

    
2538
    @Override
2539
    public List<Feature> getFeatures(String filter, String sortBy) {
2540
        return this.getFeatures(filter, sortBy, true);
2541
    }
2542

    
2543
    @Override
2544
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc) {
2545
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2546
        return this.getFeatures(query, 0);
2547
    }
2548

    
2549
    @Override
2550
    public List<Feature> getFeatures(Expression filter) {
2551
        return this.getFeatures(filter, null, true);
2552
    }
2553

    
2554
    @Override
2555
    public List<Feature> getFeatures(Expression filter, String sortBy) {
2556
        return this.getFeatures(filter, sortBy, true);
2557
    }
2558

    
2559
    @Override
2560
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc) {
2561
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2562
        return this.getFeatures(query, 0);
2563
    }
2564

    
2565
    @Override
2566
    public List<Feature> getFeatures(FeatureQuery query) {
2567
        return this.getFeatures(query, 0);
2568
    }
2569

    
2570
    @Override
2571
    public List<Feature> getFeatures(FeatureQuery query, int pageSize) {
2572
        try {
2573
            if (pageSize <= 0) {
2574
                pageSize = 100;
2575
            }
2576
            addRequiredAttributes(query);
2577
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2578
            return pager.asList();
2579
        } catch (BaseException ex) {
2580
            throw new RuntimeException("Can't create the list of features.", ex);
2581
        }
2582
    }
2583
        
2584
    @Override
2585
    public List<Feature> getFeatures() {
2586
        return this.getFeatures(null, 0);
2587
    }
2588

    
2589
    @Override
2590
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2591
        return this.getFeatures64(null, 0);
2592
    }
2593

    
2594
    @Override
2595
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2596
        return this.getFeatures64(filter, null, true);
2597
    }
2598

    
2599
    @Override
2600
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc) {
2601
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2602
        return this.getFeatures64(query, 0);
2603
    }
2604

    
2605
    @Override
2606
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize) {
2607
        try {
2608
            if (pageSize <= 0) {
2609
                pageSize = 100;
2610
            }
2611
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2612
            return pager;
2613
        } catch (BaseException ex) {
2614
            throw new RuntimeException("Can't create the list of features.", ex);
2615
        }
2616
    }
2617

    
2618
    @Override
2619
    public Feature first() throws DataException {
2620
        return this.findFirst((FeatureQuery) null);
2621
    }
2622

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

    
2628
    @Override
2629
    public Feature findFirst(String filter, String sortBy) throws DataException {
2630
        return this.findFirst(filter, sortBy, true);
2631
    }
2632

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

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

    
2645
    @Override
2646
    public Feature findFirst(Expression filter) throws DataException {
2647
        return this.findFirst(filter, (String) null, true);
2648
    }
2649

    
2650
    @Override
2651
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2652
        return this.findFirst(filter, sortBy, true);
2653
    }
2654

    
2655
    @Override
2656
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2657
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2658
        return findFirst(query);
2659
    }
2660

    
2661
    @Override
2662
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2663
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2664
        return findFirst(query);
2665
    }
2666

    
2667
    @Override
2668
    public Feature findFirst(FeatureQuery query) throws DataException {
2669
        if (query == null) {
2670
            query = this.createFeatureQuery();
2671
        } else {
2672
            query = query.getCopy();
2673
        }
2674
        query.setLimit(1);
2675
        final MutableObject<Feature> feature = new MutableObject<>();
2676
        try {
2677
            this.accept((Object obj) -> {
2678
                feature.setValue((Feature) obj);
2679
                throw new VisitCanceledException();
2680
            }, query);
2681
        } catch (VisitCanceledException ex) {
2682

    
2683
        } catch (DataException ex) {
2684
            throw ex;
2685
        } catch (Exception ex) {
2686
            throw new RuntimeException("", ex);
2687
        }
2688
        return feature.getValue();
2689
    }
2690

    
2691
    @Override
2692
    public void accept(Visitor visitor) throws BaseException {
2693
        this.accept(visitor, null);
2694
    }
2695

    
2696
    @Override
2697
    public void accept(Visitor visitor, DataQuery dataQuery)
2698
            throws BaseException {
2699
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2700
        try {
2701
            set.accept(visitor);
2702
        } finally {
2703
            set.dispose();
2704
        }
2705
    }
2706

    
2707
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2708
            throws DataException {
2709
        DefaultFeatureType fType
2710
                = (DefaultFeatureType) this.getFeatureType(featureQuery
2711
                        .getFeatureTypeId());
2712
        if (featureQuery.hasAttributeNames()
2713
                || featureQuery.hasConstantsAttributeNames()
2714
                || fType.hasRequiredFields()) {
2715
            if (featureQuery.hasGroupByColumns()) {
2716
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false);
2717
            } else {
2718
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2719
            }
2720
        }
2721
        return fType;
2722
    }
2723

    
2724
    @Override
2725
    public void getFeatureSet(Observer observer) throws DataException {
2726
        checkNotInAppendMode();
2727
        this.getFeatureSet(null, observer);
2728
    }
2729

    
2730
    @Override
2731
    public void getFeatureSet(FeatureQuery query, Observer observer)
2732
            throws DataException {
2733
        class LoadInBackGround implements Runnable {
2734

    
2735
            private final FeatureStore store;
2736
            private final FeatureQuery query;
2737
            private final Observer observer;
2738

    
2739
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2740
                    Observer observer) {
2741
                this.store = store;
2742
                this.query = query;
2743
                this.observer = observer;
2744
            }
2745

    
2746
            void notify(FeatureStoreNotification theNotification) {
2747
                observer.update(store, theNotification);
2748
            }
2749

    
2750
            @Override
2751
            public void run() {
2752
                FeatureSet set = null;
2753
                try {
2754
                    set = store.getFeatureSet(query);
2755
                    notify(new DefaultFeatureStoreNotification(store,
2756
                            FeatureStoreNotification.LOAD_FINISHED, set));
2757
                } catch (Exception e) {
2758
                    notify(new DefaultFeatureStoreNotification(store,
2759
                            FeatureStoreNotification.LOAD_FINISHED, e));
2760
                } finally {
2761
                    dispose(set);
2762
                }
2763
            }
2764
        }
2765

    
2766
        checkNotInAppendMode();
2767
        if (query == null) {
2768
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2769
        }
2770
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2771
        Thread thread = new Thread(task, "Load Feature Set in background");
2772
        thread.start();
2773
    }
2774

    
2775
    @Override
2776
    public Feature getFeatureByReference(FeatureReference reference)
2777
            throws DataException {
2778
        checkNotInAppendMode();
2779
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2780
        FeatureType featureType;
2781
        if (ref.getFeatureTypeId() == null) {
2782
            featureType = this.getDefaultFeatureType();
2783
        } else {
2784
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2785
        }
2786
        return this.getFeatureByReference(reference, featureType);
2787
    }
2788

    
2789
    @Override
2790
    public Feature getFeatureByReference(FeatureReference reference,
2791
            FeatureType featureType) throws DataException {
2792
        checkNotInAppendMode();
2793
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2794
        if (this.mode == MODE_FULLEDIT) {
2795
            Feature f = featureManager.get(reference, this, featureType);
2796
            if (f != null) {
2797
                return f;
2798
            }
2799
        }
2800

    
2801
        FeatureType sourceFeatureType = featureType;
2802
        if (!this.transforms.isEmpty()) {
2803
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2804
        }
2805
        // TODO comprobar que el id es de este store
2806

    
2807
        DefaultFeature feature
2808
                = new DefaultFeature(this,
2809
                        this.provider.getFeatureProviderByReference(
2810
                                (FeatureReferenceProviderServices) reference, sourceFeatureType));
2811

    
2812
        if (!this.transforms.isEmpty()) {
2813
            return this.transforms.applyTransform(feature, featureType);
2814
        }
2815
        return feature;
2816
    }
2817

    
2818
    //
2819
    // ====================================================================
2820
    // Gestion de features
2821
    //
2822
    private FeatureType fixFeatureType(DefaultFeatureType type)
2823
            throws DataException {
2824
        FeatureType original = this.getDefaultFeatureType();
2825

    
2826
        if ((type == null) || type.equals(original)) {
2827
            return original;
2828
        } else {
2829
            if (!type.isSubtypeOf(original)) {
2830
                Iterator iter = this.getFeatureTypes().iterator();
2831
                FeatureType tmpType;
2832
                boolean found = false;
2833
                while (iter.hasNext()) {
2834
                    tmpType = (FeatureType) iter.next();
2835
                    if (type.equals(tmpType)) {
2836
                        return type;
2837

    
2838
                    } else if (type.isSubtypeOf(tmpType)) {
2839
                        found = true;
2840
                        original = tmpType;
2841
                        break;
2842
                    }
2843

    
2844
                }
2845
                if (!found) {
2846
                    throw new IllegalFeatureTypeException(getName());
2847
                }
2848
            }
2849
        }
2850

    
2851
        // Checks that type has all fields of pk
2852
        // else add the missing attributes at the end.
2853
        if (!original.hasOID()) {
2854
            // Gets original pk attributes
2855
            DefaultEditableFeatureType edOriginal
2856
                    = (DefaultEditableFeatureType) original.getEditable();
2857
            FeatureAttributeDescriptor orgAttr;
2858
            Iterator edOriginalIter = edOriginal.iterator();
2859
            while (edOriginalIter.hasNext()) {
2860
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2861
                if (!orgAttr.isPrimaryKey()) {
2862
                    edOriginalIter.remove();
2863
                }
2864
            }
2865

    
2866
            // Checks if all pk attributes are in type
2867
            Iterator typeIterator;
2868
            edOriginalIter = edOriginal.iterator();
2869
            FeatureAttributeDescriptor attr;
2870
            while (edOriginalIter.hasNext()) {
2871
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2872
                typeIterator = type.iterator();
2873
                while (typeIterator.hasNext()) {
2874
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2875
                    if (attr.getName().equals(orgAttr.getName())) {
2876
                        edOriginalIter.remove();
2877
                        break;
2878
                    }
2879
                }
2880
            }
2881

    
2882
            // add missing pk attributes if any
2883
            if (edOriginal.size() > 0) {
2884
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2885
                DefaultEditableFeatureType edType
2886
                        = (DefaultEditableFeatureType) original.getEditable();
2887
                edType.clear();
2888
                edType.addAll(type);
2889
                edType.addAll(edOriginal);
2890
                if (!isEditable) {
2891
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2892
                }
2893
            }
2894

    
2895
        }
2896

    
2897
        return type;
2898
    }
2899

    
2900
    private void validateFeaturesAtFinishEditing() throws ValidateFeaturesException {
2901
        try {
2902
            checkInEditingMode();
2903
            FeatureType type = this.getDefaultFeatureTypeQuietly();
2904
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
2905

    
2906
            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS : 0;
2907
            checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
2908
            if (checks == 0) {
2909
                return;
2910
            }
2911

    
2912
            Iterator<EditableFeature> features = new ChainedIterator<>(
2913
                    featureManager.getInsertedFeatures(),
2914
                    featureManager.getUpdatedFeatures()
2915
            );
2916
            while (features.hasNext()) {
2917
                EditableFeature feature = features.next();
2918
                rules.validate(feature, checks);
2919
            }
2920
        } catch (Exception ex) {
2921
            throw new ValidateFeaturesException(this.getName(), ex);
2922
        }
2923
    }
2924

    
2925
    @Override
2926
    public FeatureType getDefaultFeatureType() throws DataException {
2927
        try {
2928

    
2929
            if (isEditing()) {
2930
                FeatureType auxFeatureType
2931
                        = featureTypeManager.getType(defaultFeatureType.getId());
2932
                if (auxFeatureType != null) {
2933
                    return avoidEditable(auxFeatureType);
2934
                }
2935
            }
2936
            FeatureType type = this.transforms.getDefaultFeatureType();
2937
            if (type != null) {
2938
                return avoidEditable(type);
2939
            }
2940

    
2941
            return avoidEditable(defaultFeatureType);
2942

    
2943
        } catch (Exception e) {
2944
            throw new GetFeatureTypeException(e, getName());
2945
        }
2946
    }
2947

    
2948
    @Override
2949
    public FeatureType getDefaultFeatureTypeQuietly() {
2950
        try {
2951
            return this.getDefaultFeatureType();
2952
        } catch (Exception ex) {
2953
            return null;
2954
        }
2955
    }
2956

    
2957
    private FeatureType avoidEditable(FeatureType ft) {
2958
        if (ft instanceof EditableFeatureType) {
2959
            return ((EditableFeatureType) ft).getNotEditableCopy();
2960
        } else {
2961
            return ft;
2962
        }
2963
    }
2964

    
2965
    @Override
2966
    public FeatureType getFeatureType(String featureTypeId)
2967
            throws DataException {
2968
        if (featureTypeId == null) {
2969
            return this.getDefaultFeatureType();
2970
        }
2971
        try {
2972
            if (isEditing()) {
2973
                FeatureType auxFeatureType
2974
                        = featureTypeManager.getType(featureTypeId);
2975
                if (auxFeatureType != null) {
2976
                    return auxFeatureType;
2977
                }
2978
            }
2979
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2980
            if (type != null) {
2981
                return type;
2982
            }
2983
            Iterator iter = this.featureTypes.iterator();
2984
            while (iter.hasNext()) {
2985
                type = (FeatureType) iter.next();
2986
                if (type.getId().equals(featureTypeId)) {
2987
                    return type;
2988
                }
2989
            }
2990
            return null;
2991
        } catch (Exception e) {
2992
            throw new GetFeatureTypeException(e, getName());
2993
        }
2994
    }
2995

    
2996
    public FeatureType getProviderDefaultFeatureType() {
2997
        return defaultFeatureType;
2998
    }
2999

    
3000
    @Override
3001
    public List getFeatureTypes() throws DataException {
3002
        try {
3003
            List types;
3004
            if (isEditing()) {
3005
                types = new ArrayList();
3006
                for (FeatureType type : featureTypes) {
3007
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
3008
                    if (typeaux != null) {
3009
                        types.add(typeaux);
3010
                    } else {
3011
                        types.add(type);
3012
                    }
3013
                }
3014
                Iterator it = featureTypeManager.newsIterator();
3015
                while (it.hasNext()) {
3016
                    FeatureType type = (FeatureType) it.next();
3017
                    types.add(type);
3018
                }
3019
            } else {
3020
                types = this.transforms.getFeatureTypes();
3021
                if (types == null) {
3022
                    types = featureTypes;
3023
                }
3024
            }
3025
            return Collections.unmodifiableList(types);
3026
        } catch (Exception e) {
3027
            throw new GetFeatureTypeException(e, getName());
3028
        }
3029
    }
3030

    
3031
    public List getProviderFeatureTypes() throws DataException {
3032
        return Collections.unmodifiableList(this.featureTypes);
3033
    }
3034

    
3035
    @Override
3036
    public Feature createFeature(FeatureProvider data) throws DataException {
3037
        DefaultFeature feature = new DefaultFeature(this, data);
3038
        return feature;
3039
    }
3040

    
3041
    public Feature createFeature(FeatureProvider data, FeatureType type)
3042
            throws DataException {
3043
        // FIXME: falta por implementar
3044
        // Comprobar si es un subtipo del feature de data
3045
        // y construir un feature usando el subtipo.
3046
        // Probablemente requiera generar una copia del data.
3047
        throw new NotYetImplemented();
3048
    }
3049

    
3050
    @Override
3051
    public EditableFeature createNewFeature(FeatureType type,
3052
            Feature defaultValues) throws DataException {
3053
        try {
3054
            FeatureProvider data = createNewFeatureProvider(type);
3055
            DefaultEditableFeature feature
3056
                    = new DefaultEditableFeature(this, data);
3057
            feature.initializeValues(defaultValues);
3058
            data.setNew(true);
3059

    
3060
            return feature;
3061
        } catch (Exception e) {
3062
            throw new CreateFeatureException(e, getName());
3063
        }
3064
    }
3065

    
3066
    private FeatureProvider createNewFeatureProvider(FeatureType type)
3067
            throws DataException {
3068
        type = this.fixFeatureType((DefaultFeatureType) type);
3069
        FeatureProvider data = this.provider.createFeatureProvider(type);
3070
        data.setNew(true);
3071
        if (type.hasOID() && (data.getOID() == null)) {
3072
            data.setOID(this.provider.createNewOID());
3073
        } else {
3074
            data.setOID(this.getTemporalOID());
3075
        }
3076
        return data;
3077

    
3078
    }
3079

    
3080
    @Override
3081
    public EditableFeature createNewFeature(FeatureType type,
3082
            boolean defaultValues) throws DataException {
3083
        try {
3084
            FeatureProvider data = createNewFeatureProvider(type);
3085
            DefaultEditableFeature feature
3086
                    = new DefaultEditableFeature(this, data);
3087
            if (defaultValues) {
3088
                feature.initializeValues();
3089
            }
3090
            return feature;
3091
        } catch (Exception e) {
3092
            throw new CreateFeatureException(e, getName());
3093
        }
3094
    }
3095

    
3096
    @Override
3097
    public EditableFeature createNewFeature(boolean defaultValues)
3098
            throws DataException {
3099
        return this.createNewFeature(this.getDefaultFeatureType(),
3100
                defaultValues);
3101
    }
3102

    
3103
    @Override
3104
    public EditableFeature createNewFeature() throws DataException {
3105
        return this.createNewFeature(this.getDefaultFeatureType(), true);
3106
    }
3107

    
3108
    @Override
3109
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
3110
        FeatureType ft = this.getDefaultFeatureType();
3111
        EditableFeature f = this.createNewFeature(ft, false);
3112
        f.copyFrom(defaultValues);
3113
        return f;
3114
    }
3115

    
3116
    @Override
3117
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
3118
        FeatureType ft = this.getDefaultFeatureType();
3119
        EditableFeature f = this.createNewFeature(ft, false);
3120
        f.copyFrom(defaultValues);
3121
        return f;
3122
    }
3123

    
3124
    @Override
3125
    public EditableFeatureType createFeatureType() {
3126
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
3127
        return ftype;
3128
    }
3129

    
3130
    @Override
3131
    public EditableFeatureType createFeatureType(String id) {
3132
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
3133
        return ftype;
3134
    }
3135

    
3136
    //
3137
    // ====================================================================
3138
    // Index related methods
3139
    //
3140
    @Override
3141
    public FeatureIndexes getIndexes() {
3142
        return this.indexes;
3143
    }
3144

    
3145
    @Override
3146
    public FeatureIndex createIndex(FeatureType featureType,
3147
            String attributeName, String indexName) throws DataException {
3148
        return createIndex(null, featureType, attributeName, indexName);
3149
    }
3150

    
3151
    @Override
3152
    public FeatureIndex createIndex(String indexTypeName,
3153
            FeatureType featureType, String attributeName, String indexName)
3154
            throws DataException {
3155

    
3156
        return createIndex(indexTypeName, featureType, attributeName,
3157
                indexName, false, null);
3158
    }
3159

    
3160
    @Override
3161
    public FeatureIndex createIndex(FeatureType featureType,
3162
            String attributeName, String indexName, Observer observer)
3163
            throws DataException {
3164
        return createIndex(null, featureType, attributeName, indexName,
3165
                observer);
3166
    }
3167

    
3168
    @Override
3169
    public FeatureIndex createIndex(String indexTypeName,
3170
            FeatureType featureType, String attributeName, String indexName,
3171
            final Observer observer) throws DataException {
3172

    
3173
        return createIndex(indexTypeName, featureType, attributeName,
3174
                indexName, true, observer);
3175
    }
3176

    
3177
    private FeatureIndex createIndex(String indexTypeName,
3178
            FeatureType featureType, String attributeName, String indexName,
3179
            boolean background, final Observer observer) throws DataException {
3180

    
3181
        checkNotInAppendMode();
3182
        FeatureIndexProviderServices index;
3183
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
3184
                featureType, indexName,
3185
                featureType.getAttributeDescriptor(attributeName));
3186

    
3187
        try {
3188
            index.fill(background, observer);
3189
        } catch (FeatureIndexException e) {
3190
            throw new InitializeException(index.getName(), e);
3191
        }
3192

    
3193
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
3194
        return index;
3195
    }
3196

    
3197
    //
3198
    // ====================================================================
3199
    // Transforms related methods
3200
    //
3201
    @Override
3202
    public FeatureStoreTransforms getTransforms() {
3203
        return this.transforms;
3204
    }
3205

    
3206
    @Override
3207
    public FeatureQuery createFeatureQuery() {
3208
        return new DefaultFeatureQuery(this.getName());
3209
    }
3210

    
3211
    @Override
3212
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
3213
        FeatureQuery query = null;
3214
        if ( !ExpressionUtils.isPhraseEmpty(filter) ) {
3215
            query = this.createFeatureQuery();
3216
            query.setFilter(filter);
3217
        }
3218
        if (!StringUtils.isBlank(sortBy)) {
3219
            if (query == null) {
3220
                query = this.createFeatureQuery();
3221
            }
3222
            if (StringUtils.containsAny(sortBy, "(", ")")) {
3223
                throw new IllegalArgumentException("Incorrect sortBy expression");
3224
            }
3225
            String[] attrnames;
3226
            if (sortBy.contains(",")) {
3227
                attrnames = StringUtils.split(sortBy, ",");
3228
            } else {
3229
                attrnames = new String[]{sortBy};
3230
            }
3231
            for (String attrname : attrnames) {
3232
                attrname = attrname.trim();
3233
                if (attrname.startsWith("-")) {
3234
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(1).trim(),'"'), false);
3235
                } else if (attrname.endsWith("-")) {
3236
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(0, sortBy.length() - 1).trim(),'"'), false);
3237
                } else if (attrname.startsWith("+")) {
3238
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(1).trim(),'"'), true);
3239
                } else if (attrname.endsWith("-")) {
3240
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(0, sortBy.length() - 1).trim(),'"'), true);
3241
                } else {
3242
                    query.getOrder().add(StringUtils.unwrap(attrname,'"'), asc);
3243
                }
3244
            }
3245
        }
3246
        if (query != null) {
3247
            query.retrievesAllAttributes();
3248
        }
3249
        return query;
3250
    }
3251

    
3252
    @Override
3253
    public FeatureQuery createFeatureQuery(String filter) {
3254
        return this.createFeatureQuery( 
3255
                ExpressionUtils.createExpression(filter),
3256
                (String) null,
3257
                true
3258
        );
3259
    }
3260

    
3261
    @Override
3262
    public FeatureQuery createFeatureQuery(Expression filter) {
3263
        return this.createFeatureQuery(
3264
                filter,
3265
                (String) null,
3266
                true
3267
        );
3268
    }
3269

    
3270
    @Override
3271
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
3272
        if (StringUtils.isBlank(filter)) {
3273
            return this.createFeatureQuery(
3274
                    (Expression) null,
3275
                    sortBy,
3276
                    asc
3277
            );
3278
        } else {
3279
            return this.createFeatureQuery(
3280
                    ExpressionUtils.createExpression(filter),
3281
                    sortBy,
3282
                    asc
3283
            );
3284
        }
3285
    }
3286

    
3287
    @Override
3288
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
3289
        FeatureQuery query = null;
3290
        if (filter != null) {
3291
            query = this.createFeatureQuery();
3292
            query.setFilter(filter);
3293
        }
3294
        if (sortBy != null) {
3295
            if (query == null) {
3296
                query = this.createFeatureQuery();
3297
            }
3298
            query.getOrder().add(sortBy, asc);
3299
        }
3300

    
3301
        if (query != null) {
3302
            query.retrievesAllAttributes();
3303
        }
3304
        return query;
3305
    }
3306

    
3307
    @Override
3308
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3309
        if (StringUtils.isBlank(filter)) {
3310
            return this.createFeatureQuery(
3311
                    (Expression) null,
3312
                    sortBy,
3313
                    asc
3314
            );
3315
        } else {
3316
            return this.createFeatureQuery(
3317
                    ExpressionUtils.createExpression(filter),
3318
                    sortBy,
3319
                    asc
3320
            );
3321
        }
3322
    }
3323

    
3324
    @Override
3325
    public DataQuery createQuery() {
3326
        return createFeatureQuery();
3327
    }
3328

    
3329
    //
3330
    // ====================================================================
3331
    // UndoRedo related methods
3332
    //
3333
    @Override
3334
    public boolean canRedo() {
3335
        return commands.canRedo();
3336
    }
3337

    
3338
    @Override
3339
    public boolean canUndo() {
3340
        return commands.canUndo();
3341
    }
3342

    
3343
    @Override
3344
    public void redo(int num) throws RedoException {
3345
        for (int i = 0; i < num; i++) {
3346
            redo();
3347
        }
3348
    }
3349

    
3350
    @Override
3351
    public void undo(int num) throws UndoException {
3352
        for (int i = 0; i < num; i++) {
3353
            undo();
3354
        }
3355
    }
3356

    
3357
    //
3358
    // ====================================================================
3359
    // Metadata related methods
3360
    //
3361
    @Override
3362
    public Object getMetadataID() {
3363
        return this.provider.getSourceId();
3364
    }
3365

    
3366
    @Override
3367
    public void delegate(DynObject dynObject) {
3368
        this.metadata.delegate(dynObject);
3369
    }
3370

    
3371
    @Override
3372
    public DynClass getDynClass() {
3373
        return this.metadata.getDynClass();
3374
    }
3375

    
3376
    @Override
3377
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3378
        try {
3379
            if (this.transforms.hasDynValue(name)) {
3380
                return this.transforms.getDynValue(name);
3381
            }
3382
            if (this.metadata.hasDynValue(name)) {
3383
                return this.metadata.getDynValue(name);
3384
            }
3385
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3386
                return this.provider.getProviderName();
3387
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3388
                return this.provider.getSourceId();
3389
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3390
                try {
3391
                    return this.getDefaultFeatureType();
3392
                } catch (DataException e) {
3393
                    return null;
3394
                }
3395
            }
3396
            return this.metadata.getDynValue(name);
3397
        } catch (Exception ex) {
3398
            LOGGER.debug("Can't retrieve the value of '" + name + "' in store '" + this.getName() + "'.", ex);
3399
            return null;
3400
        }
3401
    }
3402

    
3403
    @Override
3404
    public boolean hasDynValue(String name) {
3405
        if (this.transforms.hasDynValue(name)) {
3406
            return true;
3407
        }
3408
        if (this.provider.hasDynValue(name)) {
3409
            return true;
3410
        }
3411
        if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3412
            return true;
3413
        } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3414
            return true;
3415
        } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3416
            return true;
3417
        }
3418
        return this.metadata.hasDynValue(name);
3419
    }
3420

    
3421
    @Override
3422
    public boolean hasDynMethod(String name) {
3423
        return ((DynObject_v2) this.metadata).hasDynMethod(name);
3424
    }
3425

    
3426
    @Override
3427
    public void implement(DynClass dynClass) {
3428
        this.metadata.implement(dynClass);
3429
    }
3430

    
3431
    @Override
3432
    public Object invokeDynMethod(String name, Object[] args)
3433
            throws DynMethodException {
3434
        return this.metadata.invokeDynMethod(this, name, args);
3435
    }
3436

    
3437
    @Override
3438
    public Object invokeDynMethod(int code, Object[] args)
3439
            throws DynMethodException {
3440
        return this.metadata.invokeDynMethod(this, code, args);
3441
    }
3442

    
3443
    @Override
3444
    public void setDynValue(String name, Object value)
3445
            throws DynFieldNotFoundException {
3446
        if (this.transforms.hasDynValue(name)) {
3447
            this.transforms.setDynValue(name, value);
3448
            return;
3449
        }
3450
        this.metadata.setDynValue(name, value);
3451

    
3452
    }
3453

    
3454
    /*
3455
     * (non-Javadoc)
3456
     *
3457
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3458
     */
3459
    @Override
3460
    public Set getMetadataChildren() {
3461
        return this.metadataChildren;
3462
    }
3463

    
3464
    /*
3465
     * (non-Javadoc)
3466
     *
3467
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3468
     */
3469
    @Override
3470
    public String getMetadataName() {
3471
        return this.provider.getProviderName();
3472
    }
3473

    
3474
    public FeatureTypeManager getFeatureTypeManager() {
3475
        return this.featureTypeManager;
3476
    }
3477

    
3478
    @Override
3479
    public long getFeatureCount() throws DataException {
3480
        if (featureCount == null) {
3481
            featureCount = this.provider.getFeatureCount();
3482
        }
3483
        if (this.isEditing()) {
3484
            if (this.isAppending()) {
3485
                try {
3486
                    throw new IllegalStateException();
3487
                } catch (IllegalStateException e) {
3488
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND", e);
3489
                }
3490
                return -1;
3491
            } else {
3492
                return featureCount
3493
                        + this.featureManager.getDeltaSize();
3494
            }
3495
        }
3496
        return featureCount;
3497
    }
3498

    
3499
    private Long getTemporalOID() {
3500
        return this.temporalOid++;
3501
    }
3502

    
3503
    @Override
3504
    public FeatureType getProviderFeatureType(String featureTypeId) {
3505
        if (featureTypeId == null) {
3506
            return this.defaultFeatureType;
3507
        }
3508
        FeatureType type;
3509
        Iterator iter = this.featureTypes.iterator();
3510
        while (iter.hasNext()) {
3511
            type = (FeatureType) iter.next();
3512
            if (type.getId().equals(featureTypeId)) {
3513
                return type;
3514
            }
3515
        }
3516
        return null;
3517
    }
3518

    
3519
    @Override
3520
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3521
        return ((DefaultFeature) feature).getData();
3522
    }
3523

    
3524
    @Override
3525
    public DataStore getStore() {
3526
        return this;
3527
    }
3528

    
3529
    @Override
3530
    public FeatureStore getFeatureStore() {
3531
        return this;
3532
    }
3533

    
3534
    @Override
3535
    public void createCache(String name, DynObject parameters)
3536
            throws DataException {
3537
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3538
        if (cache == null) {
3539
            throw new CreateException("FeaureCacheProvider", null);
3540
        }
3541
        cache.apply(this, provider);
3542
        provider = cache;
3543

    
3544
        featureCount = null;
3545
    }
3546

    
3547
    @Override
3548
    public FeatureCache getCache() {
3549
        return cache;
3550
    }
3551

    
3552
    @Override
3553
    public void clear() {
3554
        if (metadata != null) {
3555
            metadata.clear();
3556
        }
3557
    }
3558

    
3559
    @Override
3560
    public String getName() {
3561
        if (this.provider != null) {
3562
            return this.provider.getName();
3563
        }
3564
        if (this.parameters instanceof HasAFile) {
3565
            return FilenameUtils.getName(((HasAFile) this.parameters).getFile().getName());
3566
        }
3567
        return "unknow";
3568
    }
3569

    
3570
    @Override
3571
    public String getFullName() {
3572
        try {
3573
            String fullname = null;
3574
            if (this.provider != null) {
3575
                fullname = this.provider.getFullName();
3576
            }
3577
            if ( StringUtils.isBlank(fullname) && this.parameters instanceof HasAFile) {
3578
                fullname = (((HasAFile) this.parameters).getFile().getAbsolutePath());
3579
            }
3580
            if(StringUtils.isBlank(fullNameForTraces) ) {
3581
                fullNameForTraces = fullname;
3582
            }
3583
            return fullname;
3584
        } catch (Throwable th) {
3585
            return null;
3586
        }
3587
    }
3588
    
3589
    protected String getFullNameForTraces() {
3590
        if(StringUtils.isBlank(fullNameForTraces) ) {
3591
            return this.getFullName();
3592
        }
3593
        return fullNameForTraces;
3594
    }
3595

    
3596
    @Override
3597
    public String getProviderName() {
3598
        if (this.provider != null) {
3599
            return this.provider.getProviderName();
3600
        }
3601
        if (this.parameters != null) {
3602
            return this.parameters.getDataStoreName();
3603
        }
3604
        return null;
3605

    
3606
    }
3607

    
3608
    @Override
3609
    public boolean isKnownEnvelope() {
3610
        return this.provider.isKnownEnvelope();
3611
    }
3612

    
3613
    @Override
3614
    public boolean hasRetrievedFeaturesLimit() {
3615
        return this.provider.hasRetrievedFeaturesLimit();
3616
    }
3617

    
3618
    @Override
3619
    public int getRetrievedFeaturesLimit() {
3620
        return this.provider.getRetrievedFeaturesLimit();
3621
    }
3622

    
3623
    @Override
3624
    public Interval getInterval() {
3625
        if (this.timeSupport != null) {
3626
            return this.timeSupport.getInterval();
3627
        }
3628
        try {
3629
            FeatureType type = this.getDefaultFeatureType();
3630
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3631
            if (attr != null) {
3632
                Interval interval = attr.getInterval();
3633
                if (interval != null) {
3634
                    return interval;
3635
                }
3636
            }
3637
        } catch (Exception ex) {
3638
        }
3639
        if(this.provider == null){
3640
            return null;
3641
        }
3642
        return this.provider.getInterval();
3643
    }
3644

    
3645
    @Override
3646
    public Collection getTimes() {
3647
        if (this.timeSupport != null) {
3648
            return this.timeSupport.getTimes();
3649
        }
3650
        return this.provider.getTimes();
3651
    }
3652

    
3653
    @Override
3654
    public Collection getTimes(Interval interval) {
3655
        if (this.timeSupport != null) {
3656
            return this.timeSupport.getTimes(interval);
3657
        }
3658
        return this.provider.getTimes(interval);
3659
    }
3660

    
3661
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3662
        if (this.isEditing()) {
3663
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' while store is editing.");
3664
        }
3665
        if (!this.transforms.isEmpty()) {
3666
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' if has transforms.");
3667
        }
3668
        FeatureType ft = this.defaultFeatureType;
3669
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3670
        if (attr == null) {
3671
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "', this attribute don't exists.");
3672
        }
3673
        EditableFeatureType eft = ft.getEditable();
3674
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3675
        if (attr != null) {
3676
            if (!(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport)) {
3677
                throw new RuntimeException("Can't add time support, attribute '" + timeSupport.getAttributeName() + "'already exists.");
3678
            }
3679
            eft.remove(attr.getName());
3680
        }
3681
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3682
                timeSupport.getAttributeName(),
3683
                timeSupport.getDataType()
3684
        );
3685
        attrTime.setIsTime(true);
3686
        attrTime.setFeatureAttributeEmulator(timeSupport);
3687
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3688
        this.defaultFeatureType = eft.getNotEditableCopy();
3689

    
3690
        this.timeSupport = timeSupport;
3691
    }
3692

    
3693
    @Override
3694
    @SuppressWarnings("CloneDoesntCallSuperClone")
3695
    public Object clone() throws CloneNotSupportedException {
3696

    
3697
        DataStoreParameters dsp = getParameters();
3698

    
3699
        DefaultFeatureStore cloned_store = null;
3700

    
3701
        try {
3702
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3703
                    openStore(this.getProviderName(), dsp);
3704
            if (transforms != null) {
3705
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3706
                cloned_store.transforms.setStoreForClone(cloned_store);
3707
            }
3708
        } catch (Exception e) {
3709
            throw new CloneException(e);
3710
        }
3711
        return cloned_store;
3712

    
3713
    }
3714

    
3715
    @Override
3716
    public Feature getFeature(DynObject dynobject) {
3717
        if (dynobject instanceof DynObjectFeatureFacade) {
3718
            Feature f = ((DynObjectFeatureFacade) dynobject).getFeature();
3719
            return f;
3720
        }
3721
        return null;
3722
    }
3723

    
3724
    @Override
3725
    public Iterator iterator() {
3726
        FeatureSet fset = null;
3727
        try {
3728
            fset = this.getFeatureSet();
3729
            return fset.fastIterator();
3730
        } catch (DataException ex) {
3731
            throw new RuntimeException(ex);
3732
        } finally {
3733
            DisposeUtils.disposeQuietly(fset);
3734
        }
3735
    }
3736

    
3737
    @Override
3738
    public long size64() {
3739
        FeatureSet fset = null;
3740
        try {
3741
            fset = this.getFeatureSet();
3742
            return fset.getSize();
3743
        } catch (DataException ex) {
3744
            throw new RuntimeException(ex);
3745
        } finally {
3746
            DisposeUtils.disposeQuietly(fset);
3747
        }
3748
    }
3749

    
3750
    @Override
3751
    public ExpressionBuilder createExpressionBuilder() {
3752
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3753
        return builder;
3754
    }
3755

    
3756
    @Override
3757
    public ExpressionBuilder createExpression() {
3758
        return createExpressionBuilder();
3759
    }
3760

    
3761
    public FeatureSet features() throws DataException {
3762
        // This is to avoid jython to create a property with this name
3763
        // to access method getFeatures.
3764
        return this.getFeatureSet();
3765
    }
3766

    
3767
    @Override
3768
    public DataStoreProviderFactory getProviderFactory() {
3769
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3770
        return factory;
3771
    }
3772

    
3773
    @Override
3774
    public void useCache(String providerName, DynObject parameters) throws DataException {
3775
        throw new UnsupportedOperationException();
3776
    }
3777

    
3778
    @Override
3779
    public boolean isBroken() {
3780
        return this.state.isBroken();
3781
    }
3782

    
3783
    @Override
3784
    public Throwable getBreakingsCause() {
3785
        return this.state.getBreakingsCause();
3786
    }
3787

    
3788
    @Override
3789
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3790
        FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3791
        if (!factory.supportNumericOID()) {
3792
            return null;
3793
        }
3794
        SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3795
        return wrappedIndex;
3796
    }
3797

    
3798
    @Override
3799
    public FeatureReference getFeatureReference(String code) {
3800
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3801
        return featureReference;
3802
    }
3803

    
3804
    @Override
3805
    public long getPendingChangesCount() {
3806
        if (this.featureManager == null) {
3807
            return 0;
3808
        }
3809
        return this.featureManager.getPendingChangesCount();
3810
    }
3811

    
3812
    private ResourcesStorage resourcesStorage;
3813

    
3814
    @Override
3815
    public ResourcesStorage getResourcesStorage() {
3816
        if (this.resourcesStorage != null) {
3817
            if(this.resourcesStorage instanceof SupportTransactions){
3818
                ((SupportTransactions)this.resourcesStorage).setTransaction(transaction);
3819
            } else if(this.resourcesStorage instanceof CompoundResourcesStorage) {
3820
                for (ResourcesStorage storage : (CompoundResourcesStorage)this.resourcesStorage) {
3821
                    if(storage instanceof SupportTransactions){
3822
                        ((SupportTransactions)storage).setTransaction(transaction);
3823
                    }
3824
                }
3825
            }
3826
            DisposeUtils.bind(this.resourcesStorage);
3827
            return this.resourcesStorage;
3828
        }
3829
        ResourcesStorage theResourcesStorage;
3830
        try {
3831
            theResourcesStorage = this.provider.getResourcesStorage();
3832
            if (theResourcesStorage != null) {
3833
                this.resourcesStorage = theResourcesStorage;
3834
                DisposeUtils.bind(this.resourcesStorage);
3835
                return theResourcesStorage;
3836
            }
3837
        } catch (Throwable th) {
3838

    
3839
        }
3840
        try {
3841
            DataServerExplorer explorer = this.getExplorer();
3842
            if (explorer == null) {
3843
                return null;
3844
            }
3845
            theResourcesStorage = explorer.getResourcesStorage(this);
3846
            explorer.dispose();
3847
            this.resourcesStorage = theResourcesStorage;
3848
            DisposeUtils.bind(this.resourcesStorage);
3849
            return theResourcesStorage;
3850
        } catch (Exception ex) {
3851
            LOGGER.trace("Can't create resources storage", ex);
3852
            return null;
3853
        }
3854
    }
3855

    
3856
    @Override
3857
    public StoresRepository getStoresRepository() {
3858
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3859
        StoresRepository localRepository = this.provider.getStoresRepository();
3860
        if (localRepository == null) {
3861
            return mainRepository;
3862
        }
3863
        StoresRepository repository = new BaseStoresRepository(this.getName());
3864
        repository.addRepository(localRepository);
3865
        repository.addRepository(mainRepository);
3866
        return repository;
3867
    }
3868

    
3869
    @Override
3870
    public Feature getSampleFeature() {
3871
        if( sampleFeatureCache==null )  {
3872
            this.sampleFeatureCache = new CachedValue<Feature>(sample_feature_cache_timeout_ms) {
3873
                @Override
3874
                protected void reload() {
3875
                    Feature sampleFeature;
3876
                    long t1 = System.currentTimeMillis();
3877
                    try {                        
3878
                        FeatureSelection theSelection = getFeatureSelection();
3879
                        if (theSelection != null && !theSelection.isEmpty()) {
3880
                            sampleFeature = theSelection.first();
3881
                        } else {
3882
                            sampleFeature = first();
3883
                        }
3884
                        if (sampleFeature == null) {
3885
                            sampleFeature = createNewFeature();
3886
                        }
3887
                    } catch (Exception ex) {
3888
                        sampleFeature = null;
3889
                    }
3890
                    long t2 = System.currentTimeMillis();
3891
                    if( (t2 - t1)>5000 ) {
3892
                        // Mas de 5 seg es muy costoso, subimos mucho el tiempo de cache.
3893
                        this.setExpireTime(((60*60)*2)*1000); // 2h
3894
                    }
3895
                    this.setValue(sampleFeature);
3896
                }
3897
            };
3898
        }
3899
        return this.sampleFeatureCache.get();
3900
    }
3901

    
3902
    @Override
3903
    public boolean supportReferences() {
3904
        try {
3905
            return this.getDefaultFeatureType().supportReferences();
3906
        } catch (Exception ex) {
3907
            return false;
3908
        }
3909
    }
3910

    
3911
    private Boolean temporary = null;
3912
    
3913
    @Override
3914
    public boolean isTemporary() {
3915
        if(temporary != null) {
3916
            return this.temporary;
3917
        }
3918
        if (this.provider == null) {
3919
            return true;
3920
        }
3921
        return this.provider.isTemporary();
3922
    }
3923
    
3924
    @Override
3925
    public void setTemporary(Boolean temporary){
3926
        this.temporary = temporary;
3927
    }
3928

    
3929
    public FeatureType getOriginalFeatureType(FeatureType featureType) {
3930
        // FIXME this don't work for Store.featureTypes.size() > 1
3931
        
3932
        FeatureTypeManager manager = this.featureTypeManager;
3933
        if (manager == null) {
3934
            return null;
3935
        }
3936
        FeatureType originalFeatureType = manager.getOriginalFeatureType();
3937
        if (originalFeatureType == null) {
3938
            return null;
3939
        }
3940
        return originalFeatureType.getCopy();
3941
    }
3942

    
3943
    @Override
3944
    public Object getProperty(String name) {
3945
        if (this.propertiesSupportHelper == null) {
3946
            return null;
3947
        }
3948
        return this.propertiesSupportHelper.getProperty(name);
3949
    }
3950

    
3951
    @Override
3952
    public void setProperty(String name, Object value) {
3953
        if (this.propertiesSupportHelper == null) {
3954
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3955
        }
3956
        this.propertiesSupportHelper.setProperty(name, value);
3957
    }
3958

    
3959
    @Override
3960
    public Map<String, Object> getProperties() {
3961
        if (this.propertiesSupportHelper == null) {
3962
            return Collections.EMPTY_MAP;
3963
        }
3964
        return this.propertiesSupportHelper.getProperties();
3965
    }
3966

    
3967
    @Override
3968
    public Feature getOriginalFeature(FeatureReference id) {
3969
        if (this.featureManager == null) {
3970
            return null;
3971
        }
3972
        return featureManager.getOriginal(id);
3973
    }
3974

    
3975
    @Override
3976
    public Feature getOriginalFeature(Feature feature) {
3977
        if (feature == null) {
3978
            return null;
3979
        }
3980
        return getOriginalFeature(feature.getReference());
3981
    }
3982

    
3983
    @Override
3984
    public boolean isFeatureModified(FeatureReference id) {
3985
        if (this.featureManager == null) {
3986
            return false;
3987
        }
3988
        return featureManager.isFeatureModified(id);
3989
    }
3990

    
3991
    @Override
3992
    public boolean isFeatureModified(Feature feature) {
3993
        if (feature == null) {
3994
            return false;
3995
        }
3996
        return isFeatureModified(feature.getReference());
3997
    }
3998

    
3999
    @Override
4000
    public void setTransaction(DataTransaction transaction) {
4001
        if( this.transaction!=null ) {
4002
            this.transaction.deleteObserver(transactionObserver);
4003
        }
4004
        this.transaction = transaction;
4005
        if (this.provider != null){
4006
            if (transaction == null || transaction instanceof DataTransactionServices) {
4007
                this.provider.setTransaction((DataTransactionServices) transaction);
4008
            }
4009
        }
4010
        if( transaction!=null ) {
4011
            transaction.addObserver(transactionObserver);
4012
        }
4013
    }
4014

    
4015
    @Override
4016
    public DataTransaction getTransaction() {
4017
        return transaction;
4018
    }
4019

    
4020
    @Override
4021
    public String toString() {
4022
        try {
4023
            ToStringBuilder builder = new ToStringBuilder(this);
4024
            builder.append("provider", this.provider==null? null:this.provider.getProviderName());
4025
            builder.append("fullname", this.getFullName());
4026
            return builder.toString();
4027
        } catch (Exception e) {
4028
            return super.toString();
4029
        }
4030
    }
4031

    
4032
    public String createUniqueID() {
4033
        UUID x = UUID.randomUUID();
4034
        String s = x.toString();
4035
        return s;
4036
    }
4037

    
4038
    @Override
4039
    public List<FeatureReference> getEditedFeatures() {
4040
        if( this.featureManager == null ) {
4041
            return Collections.EMPTY_LIST;
4042
        }
4043
        List<FeatureReference> references = this.featureManager.getAddedAndUpdatedFeatures();
4044
        if( references==null ) {
4045
            return Collections.EMPTY_LIST;
4046
        }
4047
        return references;
4048
    }
4049
    
4050
    public List<FeatureReference> getEditedFeaturesNotValidated() {
4051

    
4052
        try {
4053
            if (this.featureManager == null) {
4054
                return Collections.EMPTY_LIST;
4055
            }
4056
            
4057
            FeatureType type = this.getDefaultFeatureTypeQuietly();
4058
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
4059
            
4060
//            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS | CHECK_BASIC : 0;
4061
            int checks = CHECK_REQUIREDS | CHECK_BASIC;
4062
            if(type.isCheckFeaturesAtFinishEditing()){
4063
                checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
4064
            }
4065
            if (checks == 0) {
4066
                return Collections.EMPTY_LIST;
4067
            }
4068
            List<FeatureReference> references = this.featureManager
4069
                    .getAddedAndUpdatedFeaturesNotValidated(rules, checks);
4070
            if (references == null) {
4071
                return Collections.EMPTY_LIST;
4072
            }
4073
            return references;
4074
        } catch (DataException ex) {
4075
            return null;
4076
        }
4077

    
4078
    }
4079

    
4080
    @Override
4081
    public Iterator<Feature> getFeaturesIterator(Iterator<FeatureReference> references) {
4082
        return new FeatureReferenceIteratorToFeatureIterator(this, references);
4083
    }
4084

    
4085
    @Override
4086
    public Iterable<Feature> getFeaturesIterable(Iterator<FeatureReference> references) {
4087
        return () -> new FeatureReferenceIteratorToFeatureIterator(this, references);
4088
    }
4089

    
4090
    @Override
4091
    public boolean isFeatureSelectionAvailable() {
4092
        try {
4093
            FeatureType type = this.getDefaultFeatureType();
4094
            return type.supportReferences();
4095
        } catch (DataException ex) {
4096
            return false;
4097
        }
4098
    }
4099
    
4100
    @Override
4101
    public boolean canBeEdited() {
4102
        return this.transforms.isEmpty();
4103
    }
4104

    
4105
    @Override
4106
    public String getLabel() {
4107
        FeatureType ft = this.getDefaultFeatureTypeQuietly();
4108
        if( ft == null ) {
4109
            return this.getName();
4110
        }
4111
        String label = ft.getLabel();
4112
        if( StringUtils.isBlank(label) ) {
4113
            return this.getName();
4114
        }
4115
        return label;
4116
    }
4117

    
4118
    public void addRequiredAttributes(FeatureQuery fq) {
4119
        if(this.transforms != null && !this.transforms.isEmpty()){
4120
            //FIXME: A?adir solo los atributos necesarios para la transformaci?n
4121
            // this.transforms.addRequiredAttributes(fq) //No hay api todav?a
4122
            fq.retrievesAllAttributes();
4123
        }
4124
    }
4125

    
4126
    
4127
}