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

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

    
257
    private final SupportTransactionsHelper transactionHelper;
258

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

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

    
269
        private static final long serialVersionUID = 4109026189635185666L;
270

    
271
        private boolean broken;
272
        private Throwable breakingsCause;
273

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

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

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

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

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

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

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

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

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

    
337
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
338

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

    
344
        this.dataManager = (DefaultDataManager) dataManager;
345

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

    
354
    }
355

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

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

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

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

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

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

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

    
419
    public FeatureManager getFeatureManager() {
420
        return this.featureManager;
421
    }
422

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

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

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

    
463
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
464
    }
465

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

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

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

    
517
        this.featureManager = null;
518
        this.spatialManager = null;
519

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

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

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

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

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

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

    
641
    @Override
642
    public FeatureSelection createDefaultFeatureSelection()
643
            throws DataException {
644
        return new DefaultFeatureSelection(this);
645
    }
646

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

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

    
692
        }
693

    
694
        if (evaluatedAttr.isEmpty()) {
695
            evaluatedAttr = null;
696
        }
697

    
698
        state.set("evaluatedAttributes", evaluatedAttr);
699
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
700

    
701
    }
702

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

    
742
    private void load(StateInformation state) {
743
        this.featureTypes = new ArrayList();
744
        this.defaultFeatureType = null;
745
        this.featureCount = null;
746

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

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

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

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

    
815
                }
816

    
817
            }
818
        } catch (Throwable th) {
819
            state.setBreakingsCause(th);
820
        }
821

    
822
        try {
823
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
824
            FeatureType ftype;
825

    
826
            if (defaultFeatureType == null
827
                    || defaultFeatureType.getId() == null
828
                    || !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
829

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

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

    
854
    public DataStoreProviderServices getStoreProviderServices() {
855
        return this;
856
    }
857

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

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

    
890
            definition.addDynFieldObject("parameters")
891
                    .setClassOfValue(DynObject.class).setMandatory(true)
892
                    .setPersistent(true);
893

    
894
            definition.addDynFieldObject("selection")
895
                    .setClassOfValue(FeatureSelection.class).setMandatory(false)
896
                    .setPersistent(true);
897

    
898
            definition.addDynFieldObject("transforms")
899
                    .setClassOfValue(DefaultFeatureStoreTransforms.class)
900
                    .setMandatory(true).setPersistent(true);
901

    
902
            definition.addDynFieldMap("evaluatedAttributes")
903
                    .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
904
                    .setMandatory(false).setPersistent(true);
905

    
906
            definition.addDynFieldString("defaultFeatureTypeId")
907
                    .setMandatory(true).setPersistent(true);
908
        }
909
    }
910

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

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

    
930
    @Override
931
    public DataSet createSelection() throws DataException {
932
        return createFeatureSelection();
933
    }
934

    
935
    @Override
936
    public DataSet getSelection() throws DataException {
937
        return this.getFeatureSelection();
938
    }
939

    
940
    @Override
941
    public void setSelection(FeatureSet selection) throws DataException {
942
        setSelection(selection, true);
943
    }
944

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

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

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

    
1002
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1003
    }
1004

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

    
1025
    @Override
1026
    public FeatureSelection createLargeFeatureSelection() throws DataException {
1027
        return new LargeFeatureSelection(this);
1028

    
1029
    }
1030

    
1031
    @Override
1032
    public FeatureSelection createMemoryFeatureSelection() throws DataException {
1033
        return this.provider.createFeatureSelection();
1034
    }
1035

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1203
    //
1204
    // ====================================================================
1205
    // Interface Observable
1206
    //
1207
    @Override
1208
    public void disableNotifications() {
1209
        this.delegateObservable.disableNotifications();
1210

    
1211
    }
1212

    
1213
    @Override
1214
    public void enableNotifications() {
1215
        this.delegateObservable.enableNotifications();
1216
    }
1217

    
1218
    @Override
1219
    public void beginComplexNotification() {
1220
        this.delegateObservable.beginComplexNotification();
1221

    
1222
    }
1223

    
1224
    @Override
1225
    public void endComplexNotification() {
1226
        this.delegateObservable.endComplexNotification();
1227

    
1228
    }
1229

    
1230
    @Override
1231
    public void addObserver(Observer observer) {
1232
        if (delegateObservable != null) {
1233
            this.delegateObservable.addObserver(observer);
1234
        }
1235
    }
1236

    
1237
    @Override
1238
    public void deleteObserver(Observer observer) {
1239
        if (delegateObservable != null) {
1240
            this.delegateObservable.deleteObserver(observer);
1241
        }
1242
    }
1243

    
1244
    @Override
1245
    public void deleteObservers() {
1246
        this.delegateObservable.deleteObservers();
1247

    
1248
    }
1249

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

    
1268
        } else if (observable instanceof FeatureStoreProvider) {
1269
            if (observable == this.provider) {
1270

    
1271
            }
1272
        } else if (observable instanceof FeatureReferenceSelection) {
1273
            if (notification instanceof String) {
1274
                this.notifyChange((String) notification);
1275
            }
1276
        }
1277
    }
1278

    
1279
    //
1280
    // ====================================================================
1281
    // Edicion
1282
    //
1283
    private void newVersionOfUpdate() {
1284
        this.versionOfUpdate++;
1285
    }
1286

    
1287
    private long currentVersionOfUpdate() {
1288
        return this.versionOfUpdate;
1289
    }
1290

    
1291
    private void checkInEditingMode() throws NeedEditingModeException {
1292
        if (mode != MODE_FULLEDIT) {
1293
            throw new NeedEditingModeException(this.getName());
1294
        }
1295
    }
1296

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

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

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

    
1323
        if (featureTypeManager != null) {
1324
            DisposeUtils.disposeQuietly(featureTypeManager);
1325
            featureTypeManager = null;
1326

    
1327
        }
1328

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

    
1336
        featureCount = null;
1337

    
1338
        this.lastMode = this.mode;
1339
        mode = MODE_QUERY;
1340
        hasStrongChanges = true; // Lo deja a true por si las moscas
1341

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

    
1353
    @Override
1354
    synchronized public void edit() throws DataException {
1355
        edit(MODE_FULLEDIT);
1356
    }
1357

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

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

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

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

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

    
1438
    private void invalidateIndexes() {
1439
        setIndexesValidStatus(false);
1440
    }
1441

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

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

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

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

    
1498
    @Override
1499
    public boolean isEditing() {
1500
        return mode == MODE_FULLEDIT;
1501
    }
1502

    
1503
    @Override
1504
    public boolean isAppending() {
1505
        return mode == MODE_APPEND;
1506
    }
1507

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

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

    
1539
                    break;
1540
                case MODE_FULLEDIT:
1541
                    if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1542
                        return;
1543
                    }
1544
                    newVersionOfUpdate();
1545

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

    
1556
            }
1557
        } catch (Exception e) {
1558
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1559
        }
1560
    }
1561

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

    
1577
        }
1578
    }
1579

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

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

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

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

    
1649
            //Update the featureManager and the spatialManager
1650
            featureManager.delete(feature);
1651
            spatialManager.deleteFeature(feature);
1652

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

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

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

    
1682
    private static EditableFeature lastChangedFeature = null;
1683

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

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

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

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

    
1734
    synchronized public void doInsert(EditableFeature feature)
1735
            throws DataException {
1736
        checkIsOwnFeature(feature);
1737

    
1738
        waitForIndexes();
1739

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

    
1754
        featureManager.add(feature);
1755
        spatialManager.insertFeature(newFeature);
1756

    
1757
        hasStrongChanges = true;
1758
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1759
    }
1760

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

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

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

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

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

    
1867
            //Update the featureManager and the spatialManager
1868
            Feature newf = feature.getNotEditableCopy();
1869
            featureManager.update(feature, oldFeature);
1870
            spatialManager.updateFeature(newf, oldFeature);
1871

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

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

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

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

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

    
1931
    public synchronized FeatureCommandsStack getCommandsStack()
1932
            throws DataException {
1933
        checkInEditingMode();
1934
        return commands;
1935
    }
1936

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

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

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

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

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

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

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

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

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

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

    
2118
    private Map<String, List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
2119
        Map<String, List<FeatureAttributeDescriptor>> r = new HashMap<>();
2120

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

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

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

    
2158
    }
2159

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

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

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

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

    
2269
                case MODE_APPEND:
2270
                    this.provider.endAppend();
2271
                    exitEditingMode();
2272
                    invalidateIndexes();
2273
                    this.provider.beginAppend();
2274
                    break;
2275

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

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

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

    
2315
            case MODE_APPEND:
2316
                return true;
2317

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

    
2332
    @Override
2333
    public void beginEditingGroup(String description)
2334
            throws NeedEditingModeException {
2335
        checkInEditingMode();
2336
        commands.startComplex(description);
2337
    }
2338

    
2339
    @Override
2340
    public void endEditingGroup() throws NeedEditingModeException {
2341
        checkInEditingMode();
2342
        commands.endComplex();
2343
    }
2344

    
2345
    @Override
2346
    public boolean isAppendModeSupported() {
2347
        return this.provider.supportsAppendMode();
2348
    }
2349

    
2350
    @Override
2351
    public void export(DataServerExplorer explorer, String provider,
2352
            NewFeatureStoreParameters params, String name) throws DataException {
2353

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

    
2368
            }
2369
            explorer.add(provider, params, true);
2370
            DataManager manager = DALLocator.getDataManager();
2371

    
2372
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2373
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2374

    
2375
            target = (FeatureStore) manager.openStore(provider, openParams);
2376
            FeatureType targetType = target.getDefaultFeatureType();
2377

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

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

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

    
2444
    }
2445

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

    
2456
    @Override
2457
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2458
        return this.getFeatureSet((FeatureQuery)dataQuery);
2459
    }
2460

    
2461
    @Override
2462
    public void getDataSet(Observer observer) throws DataException {
2463
        checkNotInAppendMode();
2464
        this.getFeatureSet(null, observer);
2465
    }
2466

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

    
2474
    @Override
2475
    public FeatureSet getFeatureSet() throws DataException {
2476
        return this.getFeatureSet((FeatureQuery) null);
2477
    }
2478

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

    
2504
    @Override
2505
    public FeatureSet getFeatureSet(String filter) throws DataException {
2506
        return this.getFeatureSet(filter, null, true);
2507
    }
2508

    
2509
    @Override
2510
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2511
        return this.getFeatureSet(filter, sortBy, true);
2512
    }
2513

    
2514
    @Override
2515
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2516
        return this.getFeatureSet(filter, null, true);
2517
    }
2518

    
2519
    @Override
2520
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2521
        return this.getFeatureSet(filter, sortBy, true);
2522
    }
2523

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

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

    
2536
    @Override
2537
    public List<Feature> getFeatures(String filter) {
2538
        return this.getFeatures(filter, null, true);
2539
    }
2540

    
2541
    @Override
2542
    public List<Feature> getFeatures(String filter, String sortBy) {
2543
        return this.getFeatures(filter, sortBy, true);
2544
    }
2545

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

    
2552
    @Override
2553
    public List<Feature> getFeatures(Expression filter) {
2554
        return this.getFeatures(filter, null, true);
2555
    }
2556

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

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

    
2568
    @Override
2569
    public List<Feature> getFeatures(FeatureQuery query) {
2570
        return this.getFeatures(query, 0);
2571
    }
2572

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

    
2592
    @Override
2593
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2594
        return this.getFeatures64(null, 0);
2595
    }
2596

    
2597
    @Override
2598
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2599
        return this.getFeatures64(filter, null, true);
2600
    }
2601

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

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

    
2621
    @Override
2622
    public Feature first() throws DataException {
2623
        return this.findFirst((FeatureQuery) null);
2624
    }
2625

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

    
2631
    @Override
2632
    public Feature findFirst(String filter, String sortBy) throws DataException {
2633
        return this.findFirst(filter, sortBy, true);
2634
    }
2635

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

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

    
2648
    @Override
2649
    public Feature findFirst(Expression filter) throws DataException {
2650
        return this.findFirst(filter, (String) null, true);
2651
    }
2652

    
2653
    @Override
2654
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2655
        return this.findFirst(filter, sortBy, true);
2656
    }
2657

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

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

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

    
2686
        } catch (DataException ex) {
2687
            throw ex;
2688
        } catch (Exception ex) {
2689
            throw new RuntimeException("", ex);
2690
        }
2691
        return feature.getValue();
2692
    }
2693

    
2694
    @Override
2695
    public void accept(Visitor visitor) throws BaseException {
2696
        this.accept(visitor, null);
2697
    }
2698

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

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

    
2727
    @Override
2728
    public void getFeatureSet(Observer observer) throws DataException {
2729
        checkNotInAppendMode();
2730
        this.getFeatureSet(null, observer);
2731
    }
2732

    
2733
    @Override
2734
    public void getFeatureSet(FeatureQuery query, Observer observer)
2735
            throws DataException {
2736
        class LoadInBackGround implements Runnable {
2737

    
2738
            private final FeatureStore store;
2739
            private final FeatureQuery query;
2740
            private final Observer observer;
2741

    
2742
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2743
                    Observer observer) {
2744
                this.store = store;
2745
                this.query = query;
2746
                this.observer = observer;
2747
            }
2748

    
2749
            void notify(FeatureStoreNotification theNotification) {
2750
                observer.update(store, theNotification);
2751
            }
2752

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

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

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

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

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

    
2810
        DefaultFeature feature
2811
                = new DefaultFeature(this,
2812
                        this.provider.getFeatureProviderByReference(
2813
                                (FeatureReferenceProviderServices) reference, sourceFeatureType));
2814

    
2815
        if (!this.transforms.isEmpty()) {
2816
            return this.transforms.applyTransform(feature, featureType);
2817
        }
2818
        return feature;
2819
    }
2820

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

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

    
2841
                    } else if (type.isSubtypeOf(tmpType)) {
2842
                        found = true;
2843
                        original = tmpType;
2844
                        break;
2845
                    }
2846

    
2847
                }
2848
                if (!found) {
2849
                    throw new IllegalFeatureTypeException(getName());
2850
                }
2851
            }
2852
        }
2853

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

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

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

    
2898
        }
2899

    
2900
        return type;
2901
    }
2902

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

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

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

    
2928
    @Override
2929
    public FeatureType getDefaultFeatureType() throws DataException {
2930
        try {
2931

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

    
2944
            return avoidEditable(defaultFeatureType);
2945

    
2946
        } catch (Exception e) {
2947
            throw new GetFeatureTypeException(e, getName());
2948
        }
2949
    }
2950

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

    
2960
    private FeatureType avoidEditable(FeatureType ft) {
2961
        if (ft instanceof EditableFeatureType) {
2962
            return ((EditableFeatureType) ft).getNotEditableCopy();
2963
        } else {
2964
            return ft;
2965
        }
2966
    }
2967

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

    
2999
    public FeatureType getProviderDefaultFeatureType() {
3000
        return defaultFeatureType;
3001
    }
3002

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

    
3034
    public List getProviderFeatureTypes() throws DataException {
3035
        return Collections.unmodifiableList(this.featureTypes);
3036
    }
3037

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

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

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

    
3063
            return feature;
3064
        } catch (Exception e) {
3065
            throw new CreateFeatureException(e, getName());
3066
        }
3067
    }
3068

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

    
3081
    }
3082

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

    
3099
    @Override
3100
    public EditableFeature createNewFeature(boolean defaultValues)
3101
            throws DataException {
3102
        return this.createNewFeature(this.getDefaultFeatureType(),
3103
                defaultValues);
3104
    }
3105

    
3106
    @Override
3107
    public EditableFeature createNewFeature() throws DataException {
3108
        return this.createNewFeature(this.getDefaultFeatureType(), true);
3109
    }
3110

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

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

    
3127
    @Override
3128
    public EditableFeatureType createFeatureType() {
3129
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
3130
        return ftype;
3131
    }
3132

    
3133
    @Override
3134
    public EditableFeatureType createFeatureType(String id) {
3135
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
3136
        return ftype;
3137
    }
3138

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

    
3148
    @Override
3149
    public FeatureIndex createIndex(FeatureType featureType,
3150
            String attributeName, String indexName) throws DataException {
3151
        return createIndex(null, featureType, attributeName, indexName);
3152
    }
3153

    
3154
    @Override
3155
    public FeatureIndex createIndex(String indexTypeName,
3156
            FeatureType featureType, String attributeName, String indexName)
3157
            throws DataException {
3158

    
3159
        return createIndex(indexTypeName, featureType, attributeName,
3160
                indexName, false, null);
3161
    }
3162

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

    
3171
    @Override
3172
    public FeatureIndex createIndex(String indexTypeName,
3173
            FeatureType featureType, String attributeName, String indexName,
3174
            final Observer observer) throws DataException {
3175

    
3176
        return createIndex(indexTypeName, featureType, attributeName,
3177
                indexName, true, observer);
3178
    }
3179

    
3180
    private FeatureIndex createIndex(String indexTypeName,
3181
            FeatureType featureType, String attributeName, String indexName,
3182
            boolean background, final Observer observer) throws DataException {
3183

    
3184
        checkNotInAppendMode();
3185
        FeatureIndexProviderServices index;
3186
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
3187
                featureType, indexName,
3188
                featureType.getAttributeDescriptor(attributeName));
3189

    
3190
        try {
3191
            index.fill(background, observer);
3192
        } catch (FeatureIndexException e) {
3193
            throw new InitializeException(index.getName(), e);
3194
        }
3195

    
3196
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
3197
        return index;
3198
    }
3199

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

    
3209
    @Override
3210
    public FeatureQuery createFeatureQuery() {
3211
        return new DefaultFeatureQuery(this.getName());
3212
    }
3213

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

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

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

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

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

    
3304
        if (query != null) {
3305
            query.retrievesAllAttributes();
3306
        }
3307
        return query;
3308
    }
3309

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

    
3327
    @Override
3328
    public DataQuery createQuery() {
3329
        return createFeatureQuery();
3330
    }
3331

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

    
3341
    @Override
3342
    public boolean canUndo() {
3343
        return commands.canUndo();
3344
    }
3345

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

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

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

    
3369
    @Override
3370
    public void delegate(DynObject dynObject) {
3371
        this.metadata.delegate(dynObject);
3372
    }
3373

    
3374
    @Override
3375
    public DynClass getDynClass() {
3376
        return this.metadata.getDynClass();
3377
    }
3378

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

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

    
3424
    @Override
3425
    public boolean hasDynMethod(String name) {
3426
        return ((DynObject_v2) this.metadata).hasDynMethod(name);
3427
    }
3428

    
3429
    @Override
3430
    public void implement(DynClass dynClass) {
3431
        this.metadata.implement(dynClass);
3432
    }
3433

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

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

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

    
3455
    }
3456

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

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

    
3477
    public FeatureTypeManager getFeatureTypeManager() {
3478
        return this.featureTypeManager;
3479
    }
3480

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

    
3502
    private Long getTemporalOID() {
3503
        return this.temporalOid++;
3504
    }
3505

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

    
3522
    @Override
3523
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3524
        return ((DefaultFeature) feature).getData();
3525
    }
3526

    
3527
    @Override
3528
    public DataStore getStore() {
3529
        return this;
3530
    }
3531

    
3532
    @Override
3533
    public FeatureStore getFeatureStore() {
3534
        return this;
3535
    }
3536

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

    
3547
        featureCount = null;
3548
    }
3549

    
3550
    @Override
3551
    public FeatureCache getCache() {
3552
        return cache;
3553
    }
3554

    
3555
    @Override
3556
    public void clear() {
3557
        if (metadata != null) {
3558
            metadata.clear();
3559
        }
3560
    }
3561

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

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

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

    
3609
    }
3610

    
3611
    @Override
3612
    public boolean isKnownEnvelope() {
3613
        return this.provider.isKnownEnvelope();
3614
    }
3615

    
3616
    @Override
3617
    public boolean hasRetrievedFeaturesLimit() {
3618
        return this.provider.hasRetrievedFeaturesLimit();
3619
    }
3620

    
3621
    @Override
3622
    public int getRetrievedFeaturesLimit() {
3623
        return this.provider.getRetrievedFeaturesLimit();
3624
    }
3625

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

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

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

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

    
3693
        this.timeSupport = timeSupport;
3694
    }
3695

    
3696
    @Override
3697
    @SuppressWarnings("CloneDoesntCallSuperClone")
3698
    public Object clone() throws CloneNotSupportedException {
3699

    
3700
        DataStoreParameters dsp = getParameters();
3701

    
3702
        DefaultFeatureStore cloned_store = null;
3703

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

    
3716
    }
3717

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

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

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

    
3753
    @Override
3754
    public ExpressionBuilder createExpressionBuilder() {
3755
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3756
        return builder;
3757
    }
3758

    
3759
    @Override
3760
    public ExpressionBuilder createExpression() {
3761
        return createExpressionBuilder();
3762
    }
3763

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

    
3770
    @Override
3771
    public DataStoreProviderFactory getProviderFactory() {
3772
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3773
        return factory;
3774
    }
3775

    
3776
    @Override
3777
    public void useCache(String providerName, DynObject parameters) throws DataException {
3778
        throw new UnsupportedOperationException();
3779
    }
3780

    
3781
    @Override
3782
    public boolean isBroken() {
3783
        return this.state.isBroken();
3784
    }
3785

    
3786
    @Override
3787
    public Throwable getBreakingsCause() {
3788
        return this.state.getBreakingsCause();
3789
    }
3790

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

    
3801
    @Override
3802
    public FeatureReference getFeatureReference(String code) {
3803
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3804
        return featureReference;
3805
    }
3806

    
3807
    @Override
3808
    public long getPendingChangesCount() {
3809
        if (this.featureManager == null) {
3810
            return 0;
3811
        }
3812
        return this.featureManager.getPendingChangesCount();
3813
    }
3814

    
3815
    private ResourcesStorage resourcesStorage;
3816

    
3817
    @Override
3818
    public ResourcesStorage getResourcesStorage() {
3819
        if (this.resourcesStorage != null) {
3820
            if(this.resourcesStorage instanceof SupportTransactions){
3821
                ((SupportTransactions)this.resourcesStorage).setTransaction(this.getTransaction());
3822
            }
3823
            DisposeUtils.bind(this.resourcesStorage);
3824
            return this.resourcesStorage;
3825
        }
3826
        ResourcesStorage theResourcesStorage;
3827
        try {
3828
            theResourcesStorage = this.provider.getResourcesStorage();
3829
            if (theResourcesStorage != null) {
3830
                this.resourcesStorage = theResourcesStorage;
3831
                DisposeUtils.bind(this.resourcesStorage);
3832
                return theResourcesStorage;
3833
            }
3834
        } catch (Throwable th) {
3835

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

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

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

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

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

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

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

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

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

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

    
3972
    @Override
3973
    public Feature getOriginalFeature(Feature feature) {
3974
        if (feature == null) {
3975
            return null;
3976
        }
3977
        return getOriginalFeature(feature.getReference());
3978
    }
3979

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

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

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

    
4014
    @Override
4015
    public DataTransaction getTransaction() {
4016
        DataTransaction xtransaction = transactionHelper.getTransaction();
4017
        return xtransaction;
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
    @Override
4051
    public List<FeatureReference> getEditedFeaturesNotValidated() {
4052

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

    
4079
    }
4080

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

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

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

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

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

    
4127
    
4128
}