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

History | View | Annotate | Download (144 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
            // Este metodo en el proveedor da prioridad
365
            // a los parametros frente a lo que se ha leido en el fichero dal
366
            this.provider.fixFeatureTypeFromParameters();
367
            try {
368
                if (defaultFeatureType != null) {
369
                    FeatureAttributeDescriptor attrGeom = defaultFeatureType.getDefaultGeometryAttribute();
370
                    if (attrGeom != null) {
371
                        DefaultFeatureAttributeDescriptor gattr = (DefaultFeatureAttributeDescriptor) attrGeom;
372
                        IProjection srs = (IProjection) this.getDynValue(METADATA_CRS);
373
                        if (srs != null && srs != gattr.getSRS()) {
374
                            gattr.setSRSForced(srs);
375
                        }
376
                    }
377
                }
378
            } catch (Throwable th) {
379
                LOGGER.warn("Can't patch DAL file", th);
380
            }
381
        }
382
    }
383

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
694
        }
695

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

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

    
703
    }
704

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

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

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

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

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

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

    
817
                }
818

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1031
    }
1032

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1213
    }
1214

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

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

    
1224
    }
1225

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

    
1230
    }
1231

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

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

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

    
1250
    }
1251

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

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

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

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

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

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

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

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

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

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

    
1329
        }
1330

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

    
1338
        featureCount = null;
1339

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

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

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

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

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

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

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

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

    
1440
    private void invalidateIndexes() {
1441
        setIndexesValidStatus(false);
1442
    }
1443

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

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

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

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

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

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

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

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

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

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

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

    
1579
        }
1580
    }
1581

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

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

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

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

    
1651
            //Update the featureManager and the spatialManager
1652
            featureManager.delete(feature);
1653
            spatialManager.deleteFeature(feature);
1654

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

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

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

    
1684
    private static EditableFeature lastChangedFeature = null;
1685

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

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

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

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

    
1736
    synchronized public void doInsert(EditableFeature feature)
1737
            throws DataException {
1738
        checkIsOwnFeature(feature);
1739

    
1740
        waitForIndexes();
1741

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

    
1756
        featureManager.add(feature);
1757
        spatialManager.insertFeature(newFeature);
1758

    
1759
        hasStrongChanges = true;
1760
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1761
    }
1762

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2020
                case MODE_APPEND:
2021
                    if (selection != null) {
2022
                        selection = null;
2023
                    }
2024
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2025
                        return;
2026
                    }
2027
                    trans.begin();
2028
                    trans.add(this);
2029
                    saveDALFile();
2030
                    provider.endAppend();
2031
                    exitEditingMode();
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
                                    featureTypeManager.getFeatureTypesChanged().iterator());
2071
                        }
2072
                        exitEditingMode();
2073
                        loadDALFile();
2074
                        updateIndexes();
2075
                        trans.commit();
2076
                        trans.close();
2077
                    } else {
2078
                        exitEditingMode();
2079
                    }
2080
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2081
                    break;
2082
                case MODE_PASS_THROUGH:
2083
                    if (selection != null) {
2084
                        selection = null;
2085
                    }
2086
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled()) {
2087
                        return;
2088
                    }
2089
                    exitEditingMode();
2090
                    updateIndexes();
2091
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
2092
                    break;
2093
            }
2094
        } catch (ValidateFeaturesException | WriteNotAllowedException ex) {
2095
            // Don't notify failed.
2096
            trans.abortQuietly();
2097
            throw ex;
2098
        } catch (PerformEditingException pee) {
2099
            trans.abortQuietly();
2100
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2101
            throw new WriteException(provider.getSourceId().toString(), pee);
2102
        } catch (Exception e) {
2103
            trans.abortQuietly();
2104
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
2105
            throw new FinishEditingException(e);
2106
        } finally {
2107
            trans.closeQuietly();
2108
        }
2109
    }
2110
    
2111
    @Override
2112
    public String getEditingSession() {
2113
        return this.editingSessionCode;
2114
    }
2115

    
2116
    private void clearResourcesCache() {
2117
        ResourcesStorage theResourcesStorage = null;
2118
        try {
2119
            theResourcesStorage = this.getResourcesStorage();
2120
            if (theResourcesStorage == null ) {
2121
                return;
2122
            }
2123
            theResourcesStorage.clearCache();
2124
        } catch (Throwable ex) {
2125
            LOGGER.warn("Can't clear resources for store '"+this.getFullNameForTraces()+"'.", ex);
2126
        } finally {
2127
            DisposeUtils.disposeQuietly(theResourcesStorage);
2128
        }
2129
    }
2130
    
2131
    private void saveDALFile() {
2132
        if( this.ignoreDALResource ) {
2133
            return;
2134
        }
2135
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2136
        ResourcesStorage theResourcesStorage = null;
2137
        try {
2138
            theResourcesStorage = this.getResourcesStorage();
2139
            if (theResourcesStorage == null || theResourcesStorage.isReadOnly()) {
2140
                return;
2141
            }
2142
            resource = theResourcesStorage.getResource("dal");
2143
            if (resource == null || resource.isReadOnly()) {
2144
                return;
2145
            }
2146
            DALFile dalFile = DALFile.getDALFile();
2147
            dalFile.setStore(this);
2148
            if (!dalFile.isEmpty()) {
2149
                dalFile.write(resource);
2150
            }
2151
        } catch (Throwable ex) {
2152
            LOGGER.warn("Can't save DAL resource", ex);
2153
        } finally {
2154
            IOUtils.closeQuietly(resource);
2155
            DisposeUtils.disposeQuietly(theResourcesStorage);
2156
        }
2157
    }
2158

    
2159
    private void loadDALFile() {
2160
        if( this.ignoreDALResource ) {
2161
            return;
2162
        }
2163
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2164
        ResourcesStorage theResourcesStorage = null;
2165
        try {
2166
            theResourcesStorage = this.getResourcesStorage();
2167
            if (theResourcesStorage == null) {
2168
                return;
2169
            }
2170
            resource = theResourcesStorage.getResource("dal");
2171
            if (resource == null || !resource.exists()) {
2172
                return;
2173
            }
2174
            DALFile dalFile = DALFile.getDALFile(resource);
2175
            if (!dalFile.isEmpty()) {
2176
                dalFile.updateStore(this);
2177
            }
2178
        } catch (Throwable ex) {
2179
            if (resource == null || theResourcesStorage == null) {
2180
                if (theResourcesStorage == null) {
2181
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=null)", ex);
2182
                } else {
2183
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2184
                }
2185
            } else {
2186
                LOGGER.warn("Can't load DAL resource (resname=" + resource.getName() + ", resurl=" + Objects.toString(resource.getURL()) + ", storage=" + theResourcesStorage.getClass().getName() + ").", ex);
2187
            }
2188
        } finally {
2189
            IOUtils.closeQuietly(resource);
2190
            DisposeUtils.disposeQuietly(theResourcesStorage);
2191
        }
2192
    }
2193

    
2194
    /**
2195
     * Save changes in the provider without leaving the edit mode. Do not call
2196
     * observers to communicate a change of ediding mode. The operation's
2197
     * history is eliminated to prevent inconsistencies in the data.
2198
     *
2199
     * @throws DataException
2200
     */
2201
    @Override
2202
    synchronized public void commitChanges() throws DataException {
2203
        LOGGER.debug("commitChanges of mode: {}", mode);
2204
        if (!canCommitChanges()) {
2205
            throw new WriteNotAllowedException(getName());
2206
        }
2207
        try {
2208
            switch (mode) {
2209
                case MODE_QUERY:
2210
                    throw new NeedEditingModeException(this.getName());
2211

    
2212
                case MODE_APPEND:
2213
                    this.provider.endAppend();
2214
                    exitEditingMode();
2215
                    invalidateIndexes();
2216
                    this.provider.beginAppend();
2217
                    break;
2218

    
2219
                case MODE_FULLEDIT:
2220
                    if (hasStrongChanges && !this.allowWrite()) {
2221
                        throw new WriteNotAllowedException(getName());
2222
                    }
2223
                    // FIXME: OOhh!!!! no se disparan eventos, VCSGis no se entera de estos cambios.
2224
                    if (hasStrongChanges) {
2225
                        validateFeaturesAtFinishEditing();
2226
                        provider.performChanges(featureManager.getDeleted(),
2227
                                featureManager.getInserted(),
2228
                                featureManager.getUpdated(),
2229
//                                removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2230
                                featureTypeManager.getFeatureTypesChanged().iterator());
2231
                    }
2232
                    invalidateIndexes();
2233
                    featureManager = new FeatureManager(this);
2234
                    featureTypeManager = new FeatureTypeManager(this);
2235
                    spatialManager = new SpatialManager(this);
2236

    
2237
                    commands
2238
                            = new DefaultFeatureCommandsStack(this, featureManager,
2239
                                    spatialManager, featureTypeManager);
2240
                    featureCount = null;
2241
                    hasStrongChanges = false;
2242
                    break;
2243
            }
2244
        } catch (Exception e) {
2245
            throw new FinishEditingException(e);
2246
        }
2247
    }
2248

    
2249
    @Override
2250
    synchronized public boolean canCommitChanges() throws DataException {
2251
        if (!this.allowWrite()) {
2252
            return false;
2253
        }
2254
        switch (mode) {
2255
            default:
2256
            case MODE_QUERY:
2257
                return false;
2258

    
2259
            case MODE_APPEND:
2260
                return true;
2261

    
2262
            case MODE_FULLEDIT:
2263
                List types = this.getFeatureTypes();
2264
                for (int i = 0; i < types.size(); i++) {
2265
                    Object type = types.get(i);
2266
                    if (type instanceof DefaultEditableFeatureType) {
2267
                        if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
2268
                            return false;
2269
                        }
2270
                    }
2271
                }
2272
                return true;
2273
        }
2274
    }
2275

    
2276
    @Override
2277
    public void beginEditingGroup(String description)
2278
            throws NeedEditingModeException {
2279
        checkInEditingMode();
2280
        commands.startComplex(description);
2281
    }
2282

    
2283
    @Override
2284
    public void endEditingGroup() throws NeedEditingModeException {
2285
        checkInEditingMode();
2286
        commands.endComplex();
2287
    }
2288

    
2289
    @Override
2290
    public boolean isAppendModeSupported() {
2291
        return this.provider.supportsAppendMode();
2292
    }
2293

    
2294
    @Override
2295
    public void export(DataServerExplorer explorer, String provider,
2296
            NewFeatureStoreParameters params, String name) throws DataException {
2297

    
2298
        if (this.getFeatureTypes().size() != 1) {
2299
            throw new NotYetImplemented(
2300
                    "export whith more than one type not yet implemented");
2301
        }
2302
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2303
        FeatureStore target = null;
2304
        FeatureSet features = null;
2305
        DisposableIterator iterator = null;
2306
        try {
2307
            FeatureType type = this.getDefaultFeatureType();
2308
            if ((params.getDefaultFeatureType() == null)
2309
                    || (params.getDefaultFeatureType().size() == 0)) {
2310
                params.setDefaultFeatureType(type.getEditable());
2311

    
2312
            }
2313
            explorer.add(provider, params, true);
2314
            DataManager manager = DALLocator.getDataManager();
2315

    
2316
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2317
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2318

    
2319
            target = (FeatureStore) manager.openStore(provider, openParams);
2320
            FeatureType targetType = target.getDefaultFeatureType();
2321

    
2322
            target.edit(MODE_APPEND);
2323
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2324
            if (featureSelection.getSize() > 0) {
2325
                features = this.getFeatureSelection();
2326
            } else {
2327
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2328
                    FeatureQuery query = createFeatureQuery();
2329
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2330
                        query.getOrder().add(pkattr.getName(), true);
2331
                    }
2332
                    features = this.getFeatureSet(query);
2333
                } else {
2334
                    features = this.getFeatureSet();
2335
                }
2336
            }
2337
            iterator = features.fastIterator();
2338
            while (iterator.hasNext()) {
2339
                DefaultFeature feature = (DefaultFeature) iterator.next();
2340
                target.insert(target.createNewFeature(targetType, feature));
2341
            }
2342
            target.finishEditing();
2343
            target.dispose();
2344
        } catch (Exception e) {
2345
            throw new DataExportException(e, params.toString());
2346
        } finally {
2347
            dispose(iterator);
2348
            dispose(features);
2349
            dispose(target);
2350
        }
2351
    }
2352

    
2353
    @Override
2354
    public void copyTo(final FeatureStore target) {
2355
        LocalTransaction trans = new LocalTransaction(this.getDataManager(), this.getTransaction(), ((DefaultFeatureStore)target).getTransaction());
2356
        boolean finishEditingAtEnd = false;
2357
        try {
2358
            trans.begin();
2359
            trans.add(this); //Es posible que hubiera que pasarle un local a true
2360
            trans.add(target); //Es posible que hubiera que pasarle un local a true
2361
            if (!target.isEditing() && !target.isAppending()) {
2362
                finishEditingAtEnd = true;
2363
                target.edit(MODE_APPEND);
2364
            }
2365
            this.accept((Object obj) -> {
2366
                Feature f_src = (Feature) obj;
2367
                EditableFeature f_dst = target.createNewFeature(f_src);
2368
                target.insert(f_dst);
2369
            });
2370
            if (finishEditingAtEnd) {
2371
                target.finishEditing();
2372
            }
2373
            trans.commit();
2374

    
2375
        } catch (Exception ex) {
2376
            try {
2377
                if (finishEditingAtEnd) {
2378
                    target.cancelEditing();
2379
                }
2380
            } catch (Exception ex1) {
2381
            }
2382
            trans.abortQuietly();
2383
            throw new RuntimeException("Can't copy store.", ex);
2384
        } finally {
2385
            trans.closeQuietly();
2386
        }
2387

    
2388
    }
2389

    
2390
    //
2391
    // ====================================================================
2392
    // Obtencion de datos
2393
    // getDataCollection, getFeatureCollection
2394
    //
2395
    @Override
2396
    public DataSet getDataSet() throws DataException {
2397
        return this.getFeatureSet((FeatureQuery)null);
2398
    }
2399

    
2400
    @Override
2401
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2402
        return this.getFeatureSet((FeatureQuery)dataQuery);
2403
    }
2404

    
2405
    @Override
2406
    public void getDataSet(Observer observer) throws DataException {
2407
        checkNotInAppendMode();
2408
        this.getFeatureSet(null, observer);
2409
    }
2410

    
2411
    @Override
2412
    public void getDataSet(DataQuery dataQuery, Observer observer)
2413
            throws DataException {
2414
        checkNotInAppendMode();
2415
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2416
    }
2417

    
2418
    @Override
2419
    public FeatureSet getFeatureSet() throws DataException {
2420
        return this.getFeatureSet((FeatureQuery) null);
2421
    }
2422

    
2423
    @Override
2424
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2425
            throws DataException {
2426
        checkNotInAppendMode();
2427
        if (featureQuery == null) {
2428
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2429
        } else if( featureQuery.hasAggregateFunctions() || featureQuery.hasGroupByColumns() ) {
2430
            // Si tenemos datos por persistir en la bbdd (bien por que estamos en modo 
2431
            // append(batchsize) o por que estamos en modo fulledit y hay cambios
2432
            // realizados, las agrupaciones y funciones de agregado, como las gestiona
2433
            // la bbdd, pueden no dar resultados correctos. Asi que no dejamos hacer
2434
            // estas operaciones.
2435
            if( this.mode==MODE_APPEND  ) {
2436
                throw new UnsupportedOperationException("Can't create a set with aggregate functions or group by columns in append mode");
2437
            }
2438
            if( this.mode == MODE_FULLEDIT ) {
2439
                if( this.featureManager==null || this.featureManager.getPendingChangesCount()>0 ) {
2440
                   throw new UnsupportedOperationException("Can't create a set with aggregate functions or group by columns with editing changes");
2441
                }
2442
            }
2443
        }
2444
        addRequiredAttributes(featureQuery);
2445
        return new DefaultFeatureSet(this, featureQuery);
2446
    }
2447

    
2448
    @Override
2449
    public FeatureSet getFeatureSet(String filter) throws DataException {
2450
        return this.getFeatureSet(filter, null, true);
2451
    }
2452

    
2453
    @Override
2454
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2455
        return this.getFeatureSet(filter, sortBy, true);
2456
    }
2457

    
2458
    @Override
2459
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2460
        return this.getFeatureSet(filter, null, true);
2461
    }
2462

    
2463
    @Override
2464
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2465
        return this.getFeatureSet(filter, sortBy, true);
2466
    }
2467

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

    
2474
    @Override
2475
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2476
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2477
        return this.getFeatureSet(query);
2478
    }
2479

    
2480
    @Override
2481
    public List<Feature> getFeatures(String filter) {
2482
        return this.getFeatures(filter, null, true);
2483
    }
2484

    
2485
    @Override
2486
    public List<Feature> getFeatures(String filter, String sortBy) {
2487
        return this.getFeatures(filter, sortBy, true);
2488
    }
2489

    
2490
    @Override
2491
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc) {
2492
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2493
        return this.getFeatures(query, 0);
2494
    }
2495

    
2496
    @Override
2497
    public List<Feature> getFeatures(Expression filter) {
2498
        return this.getFeatures(filter, null, true);
2499
    }
2500

    
2501
    @Override
2502
    public List<Feature> getFeatures(Expression filter, String sortBy) {
2503
        return this.getFeatures(filter, sortBy, true);
2504
    }
2505

    
2506
    @Override
2507
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc) {
2508
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2509
        return this.getFeatures(query, 0);
2510
    }
2511

    
2512
    @Override
2513
    public List<Feature> getFeatures(FeatureQuery query) {
2514
        return this.getFeatures(query, 0);
2515
    }
2516

    
2517
    @Override
2518
    public List<Feature> getFeatures(FeatureQuery query, int pageSize) {
2519
        try {
2520
            if (pageSize <= 0) {
2521
                pageSize = 100;
2522
            }
2523
            addRequiredAttributes(query);
2524
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2525
            return pager.asList();
2526
        } catch (BaseException ex) {
2527
            throw new RuntimeException("Can't create the list of features.", ex);
2528
        }
2529
    }
2530
        
2531
    @Override
2532
    public List<Feature> getFeatures() {
2533
        return this.getFeatures(null, 0);
2534
    }
2535

    
2536
    @Override
2537
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2538
        return this.getFeatures64(null, 0);
2539
    }
2540

    
2541
    @Override
2542
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2543
        return this.getFeatures64(filter, null, true);
2544
    }
2545

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

    
2552
    @Override
2553
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize) {
2554
        try {
2555
            if (pageSize <= 0) {
2556
                pageSize = 100;
2557
            }
2558
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2559
            return pager;
2560
        } catch (BaseException ex) {
2561
            throw new RuntimeException("Can't create the list of features.", ex);
2562
        }
2563
    }
2564

    
2565
    @Override
2566
    public Feature first() throws DataException {
2567
        return this.findFirst((FeatureQuery) null);
2568
    }
2569

    
2570
    @Override
2571
    public Feature findFirst(String filter) throws DataException {
2572
        return this.findFirst(filter, (String) null, true);
2573
    }
2574

    
2575
    @Override
2576
    public Feature findFirst(String filter, String sortBy) throws DataException {
2577
        return this.findFirst(filter, sortBy, true);
2578
    }
2579

    
2580
    @Override
2581
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2582
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2583
        return findFirst(query);
2584
    }
2585

    
2586
    @Override
2587
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2588
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2589
        return findFirst(query);
2590
    }
2591

    
2592
    @Override
2593
    public Feature findFirst(Expression filter) throws DataException {
2594
        return this.findFirst(filter, (String) null, true);
2595
    }
2596

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

    
2602
    @Override
2603
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2604
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2605
        return findFirst(query);
2606
    }
2607

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

    
2614
    @Override
2615
    public Feature findFirst(FeatureQuery query) throws DataException {
2616
        if (query == null) {
2617
            query = this.createFeatureQuery();
2618
        } else {
2619
            query = query.getCopy();
2620
        }
2621
        query.setLimit(1);
2622
        final MutableObject<Feature> feature = new MutableObject<>();
2623
        try {
2624
            this.accept((Object obj) -> {
2625
                feature.setValue((Feature) obj);
2626
                throw new VisitCanceledException();
2627
            }, query);
2628
        } catch (VisitCanceledException ex) {
2629

    
2630
        } catch (DataException ex) {
2631
            throw ex;
2632
        } catch (Exception ex) {
2633
            throw new RuntimeException("", ex);
2634
        }
2635
        return feature.getValue();
2636
    }
2637

    
2638
    @Override
2639
    public void accept(Visitor visitor) throws BaseException {
2640
        this.accept(visitor, null);
2641
    }
2642

    
2643
    @Override
2644
    public void accept(Visitor visitor, DataQuery dataQuery)
2645
            throws BaseException {
2646
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2647
        try {
2648
            set.accept(visitor);
2649
        } finally {
2650
            set.dispose();
2651
        }
2652
    }
2653

    
2654
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2655
            throws DataException {
2656
        DefaultFeatureType fType
2657
                = (DefaultFeatureType) this.getFeatureType(featureQuery
2658
                        .getFeatureTypeId());
2659
        if (featureQuery.hasAttributeNames()
2660
                || featureQuery.hasConstantsAttributeNames()
2661
                || fType.hasRequiredFields()) {
2662
            if (featureQuery.hasGroupByColumns()) {
2663
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false);
2664
            } else {
2665
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2666
            }
2667
        }
2668
        return fType;
2669
    }
2670

    
2671
    @Override
2672
    public void getFeatureSet(Observer observer) throws DataException {
2673
        checkNotInAppendMode();
2674
        this.getFeatureSet(null, observer);
2675
    }
2676

    
2677
    @Override
2678
    public void getFeatureSet(FeatureQuery query, Observer observer)
2679
            throws DataException {
2680
        class LoadInBackGround implements Runnable {
2681

    
2682
            private final FeatureStore store;
2683
            private final FeatureQuery query;
2684
            private final Observer observer;
2685

    
2686
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2687
                    Observer observer) {
2688
                this.store = store;
2689
                this.query = query;
2690
                this.observer = observer;
2691
            }
2692

    
2693
            void notify(FeatureStoreNotification theNotification) {
2694
                observer.update(store, theNotification);
2695
            }
2696

    
2697
            @Override
2698
            public void run() {
2699
                FeatureSet set = null;
2700
                try {
2701
                    set = store.getFeatureSet(query);
2702
                    notify(new DefaultFeatureStoreNotification(store,
2703
                            FeatureStoreNotification.LOAD_FINISHED, set));
2704
                } catch (Exception e) {
2705
                    notify(new DefaultFeatureStoreNotification(store,
2706
                            FeatureStoreNotification.LOAD_FINISHED, e));
2707
                } finally {
2708
                    dispose(set);
2709
                }
2710
            }
2711
        }
2712

    
2713
        checkNotInAppendMode();
2714
        if (query == null) {
2715
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2716
        }
2717
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2718
        Thread thread = new Thread(task, "Load Feature Set in background");
2719
        thread.start();
2720
    }
2721

    
2722
    @Override
2723
    public Feature getFeatureByReference(FeatureReference reference)
2724
            throws DataException {
2725
        checkNotInAppendMode();
2726
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2727
        FeatureType featureType;
2728
        if (ref.getFeatureTypeId() == null) {
2729
            featureType = this.getDefaultFeatureType();
2730
        } else {
2731
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2732
        }
2733
        return this.getFeatureByReference(reference, featureType);
2734
    }
2735

    
2736
    @Override
2737
    public Feature getFeatureByReference(FeatureReference reference,
2738
            FeatureType featureType) throws DataException {
2739
        checkNotInAppendMode();
2740
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2741
        if (this.mode == MODE_FULLEDIT) {
2742
            Feature f = featureManager.get(reference, this, featureType);
2743
            if (f != null) {
2744
                return f;
2745
            }
2746
        }
2747

    
2748
        FeatureType sourceFeatureType = featureType;
2749
        if (!this.transforms.isEmpty()) {
2750
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2751
        }
2752
        // TODO comprobar que el id es de este store
2753

    
2754
        DefaultFeature feature
2755
                = new DefaultFeature(this,
2756
                        this.provider.getFeatureProviderByReference(
2757
                                (FeatureReferenceProviderServices) reference, sourceFeatureType));
2758

    
2759
        if (!this.transforms.isEmpty()) {
2760
            return this.transforms.applyTransform(feature, featureType);
2761
        }
2762
        return feature;
2763
    }
2764

    
2765
    //
2766
    // ====================================================================
2767
    // Gestion de features
2768
    //
2769
    private FeatureType fixFeatureType(DefaultFeatureType type)
2770
            throws DataException {
2771
        FeatureType original = this.getDefaultFeatureType();
2772

    
2773
        if ((type == null) || type.equals(original)) {
2774
            return original;
2775
        } else {
2776
            if (!type.isSubtypeOf(original)) {
2777
                Iterator iter = this.getFeatureTypes().iterator();
2778
                FeatureType tmpType;
2779
                boolean found = false;
2780
                while (iter.hasNext()) {
2781
                    tmpType = (FeatureType) iter.next();
2782
                    if (type.equals(tmpType)) {
2783
                        return type;
2784

    
2785
                    } else if (type.isSubtypeOf(tmpType)) {
2786
                        found = true;
2787
                        original = tmpType;
2788
                        break;
2789
                    }
2790

    
2791
                }
2792
                if (!found) {
2793
                    throw new IllegalFeatureTypeException(getName());
2794
                }
2795
            }
2796
        }
2797

    
2798
        // Checks that type has all fields of pk
2799
        // else add the missing attributes at the end.
2800
        if (!original.hasOID()) {
2801
            // Gets original pk attributes
2802
            DefaultEditableFeatureType edOriginal
2803
                    = (DefaultEditableFeatureType) original.getEditable();
2804
            FeatureAttributeDescriptor orgAttr;
2805
            Iterator edOriginalIter = edOriginal.iterator();
2806
            while (edOriginalIter.hasNext()) {
2807
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2808
                if (!orgAttr.isPrimaryKey()) {
2809
                    edOriginalIter.remove();
2810
                }
2811
            }
2812

    
2813
            // Checks if all pk attributes are in type
2814
            Iterator typeIterator;
2815
            edOriginalIter = edOriginal.iterator();
2816
            FeatureAttributeDescriptor attr;
2817
            while (edOriginalIter.hasNext()) {
2818
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2819
                typeIterator = type.iterator();
2820
                while (typeIterator.hasNext()) {
2821
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2822
                    if (attr.getName().equals(orgAttr.getName())) {
2823
                        edOriginalIter.remove();
2824
                        break;
2825
                    }
2826
                }
2827
            }
2828

    
2829
            // add missing pk attributes if any
2830
            if (edOriginal.size() > 0) {
2831
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2832
                DefaultEditableFeatureType edType
2833
                        = (DefaultEditableFeatureType) original.getEditable();
2834
                edType.clear();
2835
                edType.addAll(type);
2836
                edType.addAll(edOriginal);
2837
                if (!isEditable) {
2838
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2839
                }
2840
            }
2841

    
2842
        }
2843

    
2844
        return type;
2845
    }
2846

    
2847
    private void validateFeaturesAtFinishEditing() throws ValidateFeaturesException {
2848
        try {
2849
            checkInEditingMode();
2850
            FeatureType type = this.getDefaultFeatureTypeQuietly();
2851
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
2852

    
2853
            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS : 0;
2854
            checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
2855
            if (checks == 0) {
2856
                return;
2857
            }
2858

    
2859
            Iterator<EditableFeature> features = new ChainedIterator<>(
2860
                    featureManager.getInsertedFeatures(),
2861
                    featureManager.getUpdatedFeatures()
2862
            );
2863
            while (features.hasNext()) {
2864
                EditableFeature feature = features.next();
2865
                rules.validate(feature, checks);
2866
            }
2867
        } catch (Exception ex) {
2868
            throw new ValidateFeaturesException(this.getName(), ex);
2869
        }
2870
    }
2871

    
2872
    @Override
2873
    public FeatureType getDefaultFeatureType() throws DataException {
2874
        try {
2875

    
2876
            if (isEditing()) {
2877
                FeatureType auxFeatureType
2878
                        = featureTypeManager.getType(defaultFeatureType.getId());
2879
                if (auxFeatureType != null) {
2880
                    return avoidEditable(auxFeatureType);
2881
                }
2882
            }
2883
            FeatureType type = this.transforms.getDefaultFeatureType();
2884
            if (type != null) {
2885
                return avoidEditable(type);
2886
            }
2887

    
2888
            return avoidEditable(defaultFeatureType);
2889

    
2890
        } catch (Exception e) {
2891
            throw new GetFeatureTypeException(e, getName());
2892
        }
2893
    }
2894

    
2895
    @Override
2896
    public FeatureType getDefaultFeatureTypeQuietly() {
2897
        try {
2898
            return this.getDefaultFeatureType();
2899
        } catch (Exception ex) {
2900
            return null;
2901
        }
2902
    }
2903

    
2904
    private FeatureType avoidEditable(FeatureType ft) {
2905
        if (ft instanceof EditableFeatureType) {
2906
            return ((EditableFeatureType) ft).getNotEditableCopy();
2907
        } else {
2908
            return ft;
2909
        }
2910
    }
2911

    
2912
    @Override
2913
    public FeatureType getFeatureType(String featureTypeId)
2914
            throws DataException {
2915
        if (featureTypeId == null) {
2916
            return this.getDefaultFeatureType();
2917
        }
2918
        try {
2919
            if (isEditing()) {
2920
                FeatureType auxFeatureType
2921
                        = featureTypeManager.getType(featureTypeId);
2922
                if (auxFeatureType != null) {
2923
                    return auxFeatureType;
2924
                }
2925
            }
2926
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2927
            if (type != null) {
2928
                return type;
2929
            }
2930
            Iterator iter = this.featureTypes.iterator();
2931
            while (iter.hasNext()) {
2932
                type = (FeatureType) iter.next();
2933
                if (type.getId().equals(featureTypeId)) {
2934
                    return type;
2935
                }
2936
            }
2937
            return null;
2938
        } catch (Exception e) {
2939
            throw new GetFeatureTypeException(e, getName());
2940
        }
2941
    }
2942

    
2943
    public FeatureType getProviderDefaultFeatureType() {
2944
        return defaultFeatureType;
2945
    }
2946

    
2947
    @Override
2948
    public List getFeatureTypes() throws DataException {
2949
        try {
2950
            List types;
2951
            if (isEditing()) {
2952
                types = new ArrayList();
2953
                for (FeatureType type : featureTypes) {
2954
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2955
                    if (typeaux != null) {
2956
                        types.add(typeaux);
2957
                    } else {
2958
                        types.add(type);
2959
                    }
2960
                }
2961
                Iterator it = featureTypeManager.newsIterator();
2962
                while (it.hasNext()) {
2963
                    FeatureType type = (FeatureType) it.next();
2964
                    types.add(type);
2965
                }
2966
            } else {
2967
                types = this.transforms.getFeatureTypes();
2968
                if (types == null) {
2969
                    types = featureTypes;
2970
                }
2971
            }
2972
            return Collections.unmodifiableList(types);
2973
        } catch (Exception e) {
2974
            throw new GetFeatureTypeException(e, getName());
2975
        }
2976
    }
2977

    
2978
    public List getProviderFeatureTypes() throws DataException {
2979
        return Collections.unmodifiableList(this.featureTypes);
2980
    }
2981

    
2982
    @Override
2983
    public Feature createFeature(FeatureProvider data) throws DataException {
2984
        DefaultFeature feature = new DefaultFeature(this, data);
2985
        return feature;
2986
    }
2987

    
2988
    public Feature createFeature(FeatureProvider data, FeatureType type)
2989
            throws DataException {
2990
        // FIXME: falta por implementar
2991
        // Comprobar si es un subtipo del feature de data
2992
        // y construir un feature usando el subtipo.
2993
        // Probablemente requiera generar una copia del data.
2994
        throw new NotYetImplemented();
2995
    }
2996

    
2997
    @Override
2998
    public EditableFeature createNewFeature(FeatureType type,
2999
            Feature defaultValues) throws DataException {
3000
        try {
3001
            FeatureProvider data = createNewFeatureProvider(type);
3002
            DefaultEditableFeature feature
3003
                    = new DefaultEditableFeature(this, data);
3004
            feature.initializeValues(defaultValues);
3005
            data.setNew(true);
3006

    
3007
            return feature;
3008
        } catch (Exception e) {
3009
            throw new CreateFeatureException(e, getName());
3010
        }
3011
    }
3012

    
3013
    private FeatureProvider createNewFeatureProvider(FeatureType type)
3014
            throws DataException {
3015
        type = this.fixFeatureType((DefaultFeatureType) type);
3016
        FeatureProvider data = this.provider.createFeatureProvider(type);
3017
        data.setNew(true);
3018
        if (type.hasOID() && (data.getOID() == null)) {
3019
            data.setOID(this.provider.createNewOID());
3020
        } else {
3021
            data.setOID(this.getTemporalOID());
3022
        }
3023
        return data;
3024

    
3025
    }
3026

    
3027
    @Override
3028
    public EditableFeature createNewFeature(FeatureType type,
3029
            boolean defaultValues) throws DataException {
3030
        try {
3031
            FeatureProvider data = createNewFeatureProvider(type);
3032
            DefaultEditableFeature feature
3033
                    = new DefaultEditableFeature(this, data);
3034
            if (defaultValues) {
3035
                feature.initializeValues();
3036
            }
3037
            return feature;
3038
        } catch (Exception e) {
3039
            throw new CreateFeatureException(e, getName());
3040
        }
3041
    }
3042

    
3043
    @Override
3044
    public EditableFeature createNewFeature(boolean defaultValues)
3045
            throws DataException {
3046
        return this.createNewFeature(this.getDefaultFeatureType(),
3047
                defaultValues);
3048
    }
3049

    
3050
    @Override
3051
    public EditableFeature createNewFeature() throws DataException {
3052
        return this.createNewFeature(this.getDefaultFeatureType(), true);
3053
    }
3054

    
3055
    @Override
3056
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
3057
        FeatureType ft = this.getDefaultFeatureType();
3058
        EditableFeature f = this.createNewFeature(ft, false);
3059
        f.copyFrom(defaultValues);
3060
        return f;
3061
    }
3062

    
3063
    @Override
3064
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
3065
        FeatureType ft = this.getDefaultFeatureType();
3066
        EditableFeature f = this.createNewFeature(ft, false);
3067
        f.copyFrom(defaultValues);
3068
        return f;
3069
    }
3070

    
3071
    @Override
3072
    public EditableFeatureType createFeatureType() {
3073
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
3074
        return ftype;
3075
    }
3076

    
3077
    @Override
3078
    public EditableFeatureType createFeatureType(String id) {
3079
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
3080
        return ftype;
3081
    }
3082

    
3083
    //
3084
    // ====================================================================
3085
    // Index related methods
3086
    //
3087
    @Override
3088
    public FeatureIndexes getIndexes() {
3089
        return this.indexes;
3090
    }
3091

    
3092
    @Override
3093
    public FeatureIndex createIndex(FeatureType featureType,
3094
            String attributeName, String indexName) throws DataException {
3095
        return createIndex(null, featureType, attributeName, indexName);
3096
    }
3097

    
3098
    @Override
3099
    public FeatureIndex createIndex(String indexTypeName,
3100
            FeatureType featureType, String attributeName, String indexName)
3101
            throws DataException {
3102

    
3103
        return createIndex(indexTypeName, featureType, attributeName,
3104
                indexName, false, null);
3105
    }
3106

    
3107
    @Override
3108
    public FeatureIndex createIndex(FeatureType featureType,
3109
            String attributeName, String indexName, Observer observer)
3110
            throws DataException {
3111
        return createIndex(null, featureType, attributeName, indexName,
3112
                observer);
3113
    }
3114

    
3115
    @Override
3116
    public FeatureIndex createIndex(String indexTypeName,
3117
            FeatureType featureType, String attributeName, String indexName,
3118
            final Observer observer) throws DataException {
3119

    
3120
        return createIndex(indexTypeName, featureType, attributeName,
3121
                indexName, true, observer);
3122
    }
3123

    
3124
    private FeatureIndex createIndex(String indexTypeName,
3125
            FeatureType featureType, String attributeName, String indexName,
3126
            boolean background, final Observer observer) throws DataException {
3127

    
3128
        checkNotInAppendMode();
3129
        FeatureIndexProviderServices index;
3130
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
3131
                featureType, indexName,
3132
                featureType.getAttributeDescriptor(attributeName));
3133

    
3134
        try {
3135
            index.fill(background, observer);
3136
        } catch (FeatureIndexException e) {
3137
            throw new InitializeException(index.getName(), e);
3138
        }
3139

    
3140
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
3141
        return index;
3142
    }
3143

    
3144
    //
3145
    // ====================================================================
3146
    // Transforms related methods
3147
    //
3148
    @Override
3149
    public FeatureStoreTransforms getTransforms() {
3150
        return this.transforms;
3151
    }
3152

    
3153
    @Override
3154
    public FeatureQuery createFeatureQuery() {
3155
        return new DefaultFeatureQuery(this.getName());
3156
    }
3157

    
3158
    @Override
3159
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
3160
        FeatureQuery query = null;
3161
        if ( !ExpressionUtils.isPhraseEmpty(filter) ) {
3162
            query = this.createFeatureQuery();
3163
            query.setFilter(filter);
3164
        }
3165
        if (!StringUtils.isBlank(sortBy)) {
3166
            if (query == null) {
3167
                query = this.createFeatureQuery();
3168
            }
3169
            if (StringUtils.containsAny(sortBy, "(", ")")) {
3170
                throw new IllegalArgumentException("Incorrect sortBy expression");
3171
            }
3172
            String[] attrnames;
3173
            if (sortBy.contains(",")) {
3174
                attrnames = StringUtils.split(sortBy, ",");
3175
            } else {
3176
                attrnames = new String[]{sortBy};
3177
            }
3178
            for (String attrname : attrnames) {
3179
                attrname = attrname.trim();
3180
                if (attrname.startsWith("-")) {
3181
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(1).trim(),'"'), false);
3182
                } else if (attrname.endsWith("-")) {
3183
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(0, sortBy.length() - 1).trim(),'"'), false);
3184
                } else if (attrname.startsWith("+")) {
3185
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(1).trim(),'"'), true);
3186
                } else if (attrname.endsWith("-")) {
3187
                    query.getOrder().add(StringUtils.unwrap(attrname.substring(0, sortBy.length() - 1).trim(),'"'), true);
3188
                } else {
3189
                    query.getOrder().add(StringUtils.unwrap(attrname,'"'), asc);
3190
                }
3191
            }
3192
        }
3193
        if (query != null) {
3194
            query.retrievesAllAttributes();
3195
        }
3196
        return query;
3197
    }
3198

    
3199
    @Override
3200
    public FeatureQuery createFeatureQuery(String filter) {
3201
        return this.createFeatureQuery( 
3202
                ExpressionUtils.createExpression(filter),
3203
                (String) null,
3204
                true
3205
        );
3206
    }
3207

    
3208
    @Override
3209
    public FeatureQuery createFeatureQuery(Expression filter) {
3210
        return this.createFeatureQuery(
3211
                filter,
3212
                (String) null,
3213
                true
3214
        );
3215
    }
3216

    
3217
    @Override
3218
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
3219
        if (StringUtils.isBlank(filter)) {
3220
            return this.createFeatureQuery(
3221
                    (Expression) null,
3222
                    sortBy,
3223
                    asc
3224
            );
3225
        } else {
3226
            return this.createFeatureQuery(
3227
                    ExpressionUtils.createExpression(filter),
3228
                    sortBy,
3229
                    asc
3230
            );
3231
        }
3232
    }
3233

    
3234
    @Override
3235
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
3236
        FeatureQuery query = null;
3237
        if (filter != null) {
3238
            query = this.createFeatureQuery();
3239
            query.setFilter(filter);
3240
        }
3241
        if (sortBy != null) {
3242
            if (query == null) {
3243
                query = this.createFeatureQuery();
3244
            }
3245
            query.getOrder().add(sortBy, asc);
3246
        }
3247

    
3248
        if (query != null) {
3249
            query.retrievesAllAttributes();
3250
        }
3251
        return query;
3252
    }
3253

    
3254
    @Override
3255
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3256
        if (StringUtils.isBlank(filter)) {
3257
            return this.createFeatureQuery(
3258
                    (Expression) null,
3259
                    sortBy,
3260
                    asc
3261
            );
3262
        } else {
3263
            return this.createFeatureQuery(
3264
                    ExpressionUtils.createExpression(filter),
3265
                    sortBy,
3266
                    asc
3267
            );
3268
        }
3269
    }
3270

    
3271
    @Override
3272
    public DataQuery createQuery() {
3273
        return createFeatureQuery();
3274
    }
3275

    
3276
    //
3277
    // ====================================================================
3278
    // UndoRedo related methods
3279
    //
3280
    @Override
3281
    public boolean canRedo() {
3282
        return commands.canRedo();
3283
    }
3284

    
3285
    @Override
3286
    public boolean canUndo() {
3287
        return commands.canUndo();
3288
    }
3289

    
3290
    @Override
3291
    public void redo(int num) throws RedoException {
3292
        for (int i = 0; i < num; i++) {
3293
            redo();
3294
        }
3295
    }
3296

    
3297
    @Override
3298
    public void undo(int num) throws UndoException {
3299
        for (int i = 0; i < num; i++) {
3300
            undo();
3301
        }
3302
    }
3303

    
3304
    //
3305
    // ====================================================================
3306
    // Metadata related methods
3307
    //
3308
    @Override
3309
    public Object getMetadataID() {
3310
        return this.provider.getSourceId();
3311
    }
3312

    
3313
    @Override
3314
    public void delegate(DynObject dynObject) {
3315
        this.metadata.delegate(dynObject);
3316
    }
3317

    
3318
    @Override
3319
    public DynClass getDynClass() {
3320
        return this.metadata.getDynClass();
3321
    }
3322

    
3323
    @Override
3324
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3325
        try {
3326
            if (this.transforms.hasDynValue(name)) {
3327
                return this.transforms.getDynValue(name);
3328
            }
3329
            if (this.metadata.hasDynValue(name)) {
3330
                return this.metadata.getDynValue(name);
3331
            }
3332
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3333
                return this.provider.getProviderName();
3334
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3335
                return this.provider.getSourceId();
3336
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3337
                try {
3338
                    return this.getDefaultFeatureType();
3339
                } catch (DataException e) {
3340
                    return null;
3341
                }
3342
            }
3343
            return this.metadata.getDynValue(name);
3344
        } catch (Exception ex) {
3345
            LOGGER.debug("Can't retrieve the value of '" + name + "' in store '" + this.getName() + "'.", ex);
3346
            return null;
3347
        }
3348
    }
3349

    
3350
    @Override
3351
    public boolean hasDynValue(String name) {
3352
        if (this.transforms.hasDynValue(name)) {
3353
            return true;
3354
        }
3355
        if (this.provider.hasDynValue(name)) {
3356
            return true;
3357
        }
3358
        if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3359
            return true;
3360
        } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3361
            return true;
3362
        } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3363
            return true;
3364
        }
3365
        return this.metadata.hasDynValue(name);
3366
    }
3367

    
3368
    @Override
3369
    public boolean hasDynMethod(String name) {
3370
        return ((DynObject_v2) this.metadata).hasDynMethod(name);
3371
    }
3372

    
3373
    @Override
3374
    public void implement(DynClass dynClass) {
3375
        this.metadata.implement(dynClass);
3376
    }
3377

    
3378
    @Override
3379
    public Object invokeDynMethod(String name, Object[] args)
3380
            throws DynMethodException {
3381
        return this.metadata.invokeDynMethod(this, name, args);
3382
    }
3383

    
3384
    @Override
3385
    public Object invokeDynMethod(int code, Object[] args)
3386
            throws DynMethodException {
3387
        return this.metadata.invokeDynMethod(this, code, args);
3388
    }
3389

    
3390
    @Override
3391
    public void setDynValue(String name, Object value)
3392
            throws DynFieldNotFoundException {
3393
        if (this.transforms.hasDynValue(name)) {
3394
            this.transforms.setDynValue(name, value);
3395
            return;
3396
        }
3397
        this.metadata.setDynValue(name, value);
3398

    
3399
    }
3400

    
3401
    /*
3402
     * (non-Javadoc)
3403
     *
3404
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3405
     */
3406
    @Override
3407
    public Set getMetadataChildren() {
3408
        return this.metadataChildren;
3409
    }
3410

    
3411
    /*
3412
     * (non-Javadoc)
3413
     *
3414
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3415
     */
3416
    @Override
3417
    public String getMetadataName() {
3418
        return this.provider.getProviderName();
3419
    }
3420

    
3421
    public FeatureTypeManager getFeatureTypeManager() {
3422
        return this.featureTypeManager;
3423
    }
3424

    
3425
    @Override
3426
    public long getFeatureCount() throws DataException {
3427
        if (featureCount == null) {
3428
            featureCount = this.provider.getFeatureCount();
3429
        }
3430
        if (this.isEditing()) {
3431
            if (this.isAppending()) {
3432
                try {
3433
                    throw new IllegalStateException();
3434
                } catch (IllegalStateException e) {
3435
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND", e);
3436
                }
3437
                return -1;
3438
            } else {
3439
                return featureCount
3440
                        + this.featureManager.getDeltaSize();
3441
            }
3442
        }
3443
        return featureCount;
3444
    }
3445

    
3446
    private Long getTemporalOID() {
3447
        return this.temporalOid++;
3448
    }
3449

    
3450
    @Override
3451
    public FeatureType getProviderFeatureType(String featureTypeId) {
3452
        if (featureTypeId == null) {
3453
            return this.defaultFeatureType;
3454
        }
3455
        FeatureType type;
3456
        Iterator iter = this.featureTypes.iterator();
3457
        while (iter.hasNext()) {
3458
            type = (FeatureType) iter.next();
3459
            if (type.getId().equals(featureTypeId)) {
3460
                return type;
3461
            }
3462
        }
3463
        return null;
3464
    }
3465

    
3466
    @Override
3467
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3468
        return ((DefaultFeature) feature).getData();
3469
    }
3470

    
3471
    @Override
3472
    public DataStore getStore() {
3473
        return this;
3474
    }
3475

    
3476
    @Override
3477
    public FeatureStore getFeatureStore() {
3478
        return this;
3479
    }
3480

    
3481
    @Override
3482
    public void createCache(String name, DynObject parameters)
3483
            throws DataException {
3484
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3485
        if (cache == null) {
3486
            throw new CreateException("FeaureCacheProvider", null);
3487
        }
3488
        cache.apply(this, provider);
3489
        provider = cache;
3490

    
3491
        featureCount = null;
3492
    }
3493

    
3494
    @Override
3495
    public FeatureCache getCache() {
3496
        return cache;
3497
    }
3498

    
3499
    @Override
3500
    public void clear() {
3501
        if (metadata != null) {
3502
            metadata.clear();
3503
        }
3504
    }
3505

    
3506
    @Override
3507
    public String getName() {
3508
        if (this.provider != null) {
3509
            return this.provider.getName();
3510
        }
3511
        if (this.parameters instanceof HasAFile) {
3512
            return FilenameUtils.getName(((HasAFile) this.parameters).getFile().getName());
3513
        }
3514
        return "unknow";
3515
    }
3516

    
3517
    @Override
3518
    public String getFullName() {
3519
        try {
3520
            String fullname = null;
3521
            if (this.provider != null) {
3522
                fullname = this.provider.getFullName();
3523
            }
3524
            if ( StringUtils.isBlank(fullname) && this.parameters instanceof HasAFile) {
3525
                fullname = (((HasAFile) this.parameters).getFile().getAbsolutePath());
3526
            }
3527
            if(StringUtils.isBlank(fullNameForTraces) ) {
3528
                fullNameForTraces = fullname;
3529
            }
3530
            return fullname;
3531
        } catch (Throwable th) {
3532
            return null;
3533
        }
3534
    }
3535
    
3536
    protected String getFullNameForTraces() {
3537
        if(StringUtils.isBlank(fullNameForTraces) ) {
3538
            return this.getFullName();
3539
        }
3540
        return fullNameForTraces;
3541
    }
3542

    
3543
    @Override
3544
    public String getProviderName() {
3545
        if (this.provider != null) {
3546
            return this.provider.getProviderName();
3547
        }
3548
        if (this.parameters != null) {
3549
            return this.parameters.getDataStoreName();
3550
        }
3551
        return null;
3552

    
3553
    }
3554

    
3555
    @Override
3556
    public boolean isKnownEnvelope() {
3557
        return this.provider.isKnownEnvelope();
3558
    }
3559

    
3560
    @Override
3561
    public boolean hasRetrievedFeaturesLimit() {
3562
        return this.provider.hasRetrievedFeaturesLimit();
3563
    }
3564

    
3565
    @Override
3566
    public int getRetrievedFeaturesLimit() {
3567
        return this.provider.getRetrievedFeaturesLimit();
3568
    }
3569

    
3570
    @Override
3571
    public Interval getInterval() {
3572
        if (this.timeSupport != null) {
3573
            return this.timeSupport.getInterval();
3574
        }
3575
        try {
3576
            FeatureType type = this.getDefaultFeatureType();
3577
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3578
            if (attr != null) {
3579
                Interval interval = attr.getInterval();
3580
                if (interval != null) {
3581
                    return interval;
3582
                }
3583
            }
3584
        } catch (Exception ex) {
3585
        }
3586
        if(this.provider == null){
3587
            return null;
3588
        }
3589
        return this.provider.getInterval();
3590
    }
3591

    
3592
    @Override
3593
    public Collection getTimes() {
3594
        if (this.timeSupport != null) {
3595
            return this.timeSupport.getTimes();
3596
        }
3597
        return this.provider.getTimes();
3598
    }
3599

    
3600
    @Override
3601
    public Collection getTimes(Interval interval) {
3602
        if (this.timeSupport != null) {
3603
            return this.timeSupport.getTimes(interval);
3604
        }
3605
        return this.provider.getTimes(interval);
3606
    }
3607

    
3608
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3609
        if (this.isEditing()) {
3610
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' while store is editing.");
3611
        }
3612
        if (!this.transforms.isEmpty()) {
3613
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' if has transforms.");
3614
        }
3615
        FeatureType ft = this.defaultFeatureType;
3616
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3617
        if (attr == null) {
3618
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "', this attribute don't exists.");
3619
        }
3620
        EditableFeatureType eft = ft.getEditable();
3621
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3622
        if (attr != null) {
3623
            if (!(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport)) {
3624
                throw new RuntimeException("Can't add time support, attribute '" + timeSupport.getAttributeName() + "'already exists.");
3625
            }
3626
            eft.remove(attr.getName());
3627
        }
3628
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3629
                timeSupport.getAttributeName(),
3630
                timeSupport.getDataType()
3631
        );
3632
        attrTime.setIsTime(true);
3633
        attrTime.setFeatureAttributeEmulator(timeSupport);
3634
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3635
        this.defaultFeatureType = eft.getNotEditableCopy();
3636

    
3637
        this.timeSupport = timeSupport;
3638
    }
3639

    
3640
    @Override
3641
    @SuppressWarnings("CloneDoesntCallSuperClone")
3642
    public Object clone() throws CloneNotSupportedException {
3643

    
3644
        DataStoreParameters dsp = getParameters();
3645

    
3646
        DefaultFeatureStore cloned_store = null;
3647

    
3648
        try {
3649
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3650
                    openStore(this.getProviderName(), dsp);
3651
            if (transforms != null) {
3652
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3653
                cloned_store.transforms.setStoreForClone(cloned_store);
3654
            }
3655
        } catch (Exception e) {
3656
            throw new CloneException(e);
3657
        }
3658
        return cloned_store;
3659

    
3660
    }
3661

    
3662
    @Override
3663
    public Feature getFeature(DynObject dynobject) {
3664
        if (dynobject instanceof DynObjectFeatureFacade) {
3665
            Feature f = ((DynObjectFeatureFacade) dynobject).getFeature();
3666
            return f;
3667
        }
3668
        return null;
3669
    }
3670

    
3671
    @Override
3672
    public Iterator iterator() {
3673
        FeatureSet fset = null;
3674
        try {
3675
            fset = this.getFeatureSet();
3676
            return fset.fastIterator();
3677
        } catch (DataException ex) {
3678
            throw new RuntimeException(ex);
3679
        } finally {
3680
            DisposeUtils.disposeQuietly(fset);
3681
        }
3682
    }
3683

    
3684
    @Override
3685
    public long size64() {
3686
        FeatureSet fset = null;
3687
        try {
3688
            fset = this.getFeatureSet();
3689
            return fset.getSize();
3690
        } catch (DataException ex) {
3691
            throw new RuntimeException(ex);
3692
        } finally {
3693
            DisposeUtils.disposeQuietly(fset);
3694
        }
3695
    }
3696

    
3697
    @Override
3698
    public ExpressionBuilder createExpressionBuilder() {
3699
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3700
        return builder;
3701
    }
3702

    
3703
    @Override
3704
    public ExpressionBuilder createExpression() {
3705
        return createExpressionBuilder();
3706
    }
3707

    
3708
    public FeatureSet features() throws DataException {
3709
        // This is to avoid jython to create a property with this name
3710
        // to access method getFeatures.
3711
        return this.getFeatureSet();
3712
    }
3713

    
3714
    @Override
3715
    public DataStoreProviderFactory getProviderFactory() {
3716
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3717
        return factory;
3718
    }
3719

    
3720
    @Override
3721
    public void useCache(String providerName, DynObject parameters) throws DataException {
3722
        throw new UnsupportedOperationException();
3723
    }
3724

    
3725
    @Override
3726
    public boolean isBroken() {
3727
        return this.state.isBroken();
3728
    }
3729

    
3730
    @Override
3731
    public Throwable getBreakingsCause() {
3732
        return this.state.getBreakingsCause();
3733
    }
3734

    
3735
    @Override
3736
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3737
        FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3738
        if (!factory.supportNumericOID()) {
3739
            return null;
3740
        }
3741
        SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3742
        return wrappedIndex;
3743
    }
3744

    
3745
    @Override
3746
    public FeatureReference getFeatureReference(String code) {
3747
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3748
        return featureReference;
3749
    }
3750

    
3751
    @Override
3752
    public long getPendingChangesCount() {
3753
        if (this.featureManager == null) {
3754
            return 0;
3755
        }
3756
        return this.featureManager.getPendingChangesCount();
3757
    }
3758

    
3759
    private ResourcesStorage resourcesStorage;
3760

    
3761
    @Override
3762
    public ResourcesStorage getResourcesStorage() {
3763
        if (this.resourcesStorage != null) {
3764
            if(this.resourcesStorage instanceof SupportTransactions){
3765
                if( this.getTransaction()!=null ) {
3766
                    try {
3767
                        this.getTransaction().add(((SupportTransactions)this.resourcesStorage), false);
3768
                    } catch (DataException ex) {
3769
                        LOGGER.warn("Can't get resources storage, don't add to transaction",ex);
3770
                        return null;
3771
                    }
3772
                }
3773
//                ((SupportTransactions)this.resourcesStorage).setTransaction(this.getTransaction());
3774
            }
3775
            DisposeUtils.bind(this.resourcesStorage);
3776
            return this.resourcesStorage;
3777
        }
3778
        ResourcesStorage theResourcesStorage;
3779
        try {
3780
            theResourcesStorage = this.provider.getResourcesStorage();
3781
            if (theResourcesStorage != null) {
3782
                this.resourcesStorage = theResourcesStorage;
3783
                DisposeUtils.bind(this.resourcesStorage);
3784
                return theResourcesStorage;
3785
            }
3786
        } catch (Throwable th) {
3787

    
3788
        }
3789
        try {
3790
            DataServerExplorer explorer = this.getExplorer();
3791
            if (explorer == null) {
3792
                return null;
3793
            }
3794
            theResourcesStorage = explorer.getResourcesStorage(this);
3795
            explorer.dispose();
3796
            this.resourcesStorage = theResourcesStorage;
3797
            DisposeUtils.bind(this.resourcesStorage);
3798
            return theResourcesStorage;
3799
        } catch (Exception ex) {
3800
            LOGGER.trace("Can't create resources storage", ex);
3801
            return null;
3802
        }
3803
    }
3804

    
3805
    @Override
3806
    public StoresRepository getStoresRepository() {
3807
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3808
        StoresRepository localRepository = this.provider.getStoresRepository();
3809
        if (localRepository == null) {
3810
            return mainRepository;
3811
        }
3812
        StoresRepository repository = new BaseStoresRepository(this.getName());
3813
        repository.addRepository(localRepository);
3814
        repository.addRepository(mainRepository);
3815
        return repository;
3816
    }
3817

    
3818
    @Override
3819
    public Feature getSampleFeature() {
3820
        if( sampleFeatureCache==null )  {
3821
            this.sampleFeatureCache = new CachedValue<Feature>(sample_feature_cache_timeout_ms) {
3822
                @Override
3823
                protected void reload() {
3824
                    Feature sampleFeature;
3825
                    long t1 = System.currentTimeMillis();
3826
                    try {                        
3827
                        FeatureSelection theSelection = getFeatureSelection();
3828
                        if (theSelection != null && !theSelection.isEmpty()) {
3829
                            sampleFeature = theSelection.first();
3830
                        } else {
3831
                            sampleFeature = first();
3832
                        }
3833
                        if (sampleFeature == null) {
3834
                            sampleFeature = createNewFeature();
3835
                        }
3836
                    } catch (Exception ex) {
3837
                        sampleFeature = null;
3838
                    }
3839
                    long t2 = System.currentTimeMillis();
3840
                    if( (t2 - t1)>5000 ) {
3841
                        // Mas de 5 seg es muy costoso, subimos mucho el tiempo de cache.
3842
                        this.setExpireTime(((60*60)*2)*1000); // 2h
3843
                    }
3844
                    this.setValue(sampleFeature);
3845
                }
3846
            };
3847
        }
3848
        return this.sampleFeatureCache.get();
3849
    }
3850

    
3851
    @Override
3852
    public boolean supportReferences() {
3853
        try {
3854
            return this.getDefaultFeatureType().supportReferences();
3855
        } catch (Exception ex) {
3856
            return false;
3857
        }
3858
    }
3859

    
3860
    private Boolean temporary = null;
3861
    
3862
    @Override
3863
    public boolean isTemporary() {
3864
        if(temporary != null) {
3865
            return this.temporary;
3866
        }
3867
        if (this.provider == null) {
3868
            return true;
3869
        }
3870
        return this.provider.isTemporary();
3871
    }
3872
    
3873
    @Override
3874
    public void setTemporary(Boolean temporary){
3875
        this.temporary = temporary;
3876
    }
3877

    
3878
    public FeatureType getOriginalFeatureType(FeatureType featureType) {
3879
        // FIXME this don't work for Store.featureTypes.size() > 1
3880
        
3881
        FeatureTypeManager manager = this.featureTypeManager;
3882
        if (manager == null) {
3883
            return null;
3884
        }
3885
        FeatureType originalFeatureType = manager.getOriginalFeatureType();
3886
        if (originalFeatureType == null) {
3887
            return null;
3888
        }
3889
        return originalFeatureType.getCopy();
3890
    }
3891

    
3892
    @Override
3893
    public Object getProperty(String name) {
3894
        if (this.propertiesSupportHelper == null) {
3895
            return null;
3896
        }
3897
        return this.propertiesSupportHelper.getProperty(name);
3898
    }
3899

    
3900
    @Override
3901
    public void setProperty(String name, Object value) {
3902
        if (this.propertiesSupportHelper == null) {
3903
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3904
        }
3905
        this.propertiesSupportHelper.setProperty(name, value);
3906
    }
3907

    
3908
    @Override
3909
    public Map<String, Object> getProperties() {
3910
        if (this.propertiesSupportHelper == null) {
3911
            return Collections.EMPTY_MAP;
3912
        }
3913
        return this.propertiesSupportHelper.getProperties();
3914
    }
3915

    
3916
    @Override
3917
    public Feature getOriginalFeature(FeatureReference id) {
3918
        if (this.featureManager == null) {
3919
            return null;
3920
        }
3921
        return featureManager.getOriginal(id);
3922
    }
3923

    
3924
    @Override
3925
    public Feature getOriginalFeature(Feature feature) {
3926
        if (feature == null) {
3927
            return null;
3928
        }
3929
        return getOriginalFeature(feature.getReference());
3930
    }
3931

    
3932
    @Override
3933
    public boolean isFeatureModified(FeatureReference id) {
3934
        if (this.featureManager == null) {
3935
            return false;
3936
        }
3937
        return featureManager.isFeatureModified(id);
3938
    }
3939

    
3940
    @Override
3941
    public boolean isFeatureModified(Feature feature) {
3942
        if (feature == null) {
3943
            return false;
3944
        }
3945
        return isFeatureModified(feature.getReference());
3946
    }
3947
    
3948

    
3949
    @Override
3950
    public void setTransaction(DataTransaction transaction) {
3951
        DataTransaction prevTransaction = transactionHelper.getTransaction();
3952
        if( prevTransaction!=null ) {
3953
            prevTransaction.deleteObserver(transactionObserver);
3954
        }
3955
        this.transactionHelper.setTransaction(transaction);
3956
        if (this.provider != null){
3957
            if (transaction == null || transaction instanceof DataTransactionServices) {
3958
                this.provider.setTransaction((DataTransactionServices) transaction);
3959
            }
3960
        }
3961
        if( transaction!=null ) {
3962
            transaction.addObserver(transactionObserver);
3963
        }
3964
    }
3965

    
3966
    @Override
3967
    public DataTransaction getTransaction() {
3968
        DataTransaction xtransaction = transactionHelper.getTransaction();
3969
        return xtransaction;
3970
    }
3971

    
3972
    @Override
3973
    public String toString() {
3974
        try {
3975
            ToStringBuilder builder = new ToStringBuilder(this);
3976
            builder.append("provider", this.provider==null? null:this.provider.getProviderName());
3977
            builder.append("fullname", this.getFullName());
3978
            return builder.toString();
3979
        } catch (Exception e) {
3980
            return super.toString();
3981
        }
3982
    }
3983

    
3984
    public String createUniqueID() {
3985
        UUID x = UUID.randomUUID();
3986
        String s = x.toString();
3987
        return s;
3988
    }
3989

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

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

    
4031
    }
4032

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

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

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

    
4058
    @Override
4059
    public String getLabel() {
4060
        FeatureType ft = this.getDefaultFeatureTypeQuietly();
4061
        if( ft == null ) {
4062
            return this.getName();
4063
        }
4064
        String label = ft.getLabel();
4065
        if( StringUtils.isBlank(label) ) {
4066
            return this.getName();
4067
        }
4068
        return label;
4069
    }
4070

    
4071
    public void addRequiredAttributes(FeatureQuery fq) {
4072
        if(this.transforms != null && !this.transforms.isEmpty()){
4073
            //FIXME: A?adir solo los atributos necesarios para la transformaci?n
4074
            // this.transforms.addRequiredAttributes(fq) //No hay api todav?a
4075
            fq.retrievesAllAttributes();
4076
        }
4077
    }
4078

    
4079
    
4080
}