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

History | View | Annotate | Download (131 KB)

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

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

    
187
@SuppressWarnings("UseSpecificCatch")
188
public class DefaultFeatureStore extends AbstractDataStore implements
189
        DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore,
190
        SupportTransactions, Observer {
191

    
192
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
193

    
194
    private DataStoreParameters parameters = null;
195
    private FeatureSelection selection;
196
    private FeatureLocks locks;
197

    
198
    private DelegateWeakReferencingObservable delegateObservable
199
            = new DelegateWeakReferencingObservable(this);
200

    
201
    private FeatureCommandsStack commands;
202

    
203
    /*
204
    TODO: Sustituir estos tres manager por un EditingManager
205
     */
206
    private FeatureTypeManager featureTypeManager;
207
    private FeatureManager featureManager;
208
    private SpatialManager spatialManager;
209

    
210
    private FeatureType defaultFeatureType = null;
211
    private List<FeatureType> featureTypes = new ArrayList<>();
212

    
213
    private int mode = MODE_QUERY;
214
    private long versionOfUpdate = 0;
215
    private boolean hasStrongChanges = true;
216
    private boolean hasInserts = true;
217

    
218
    private DefaultDataManager dataManager = null;
219

    
220
    private FeatureStoreProvider provider = null;
221

    
222
    private DefaultFeatureIndexes indexes;
223

    
224
    private DefaultFeatureStoreTransforms transforms;
225

    
226
    /*friend*/ DelegatedDynObject metadata;
227

    
228
    private Set metadataChildren;
229

    
230
    private Long featureCount = null;
231

    
232
    private long temporalOid = 0;
233

    
234
    private FeatureCacheProvider cache;
235

    
236
    private final StateInformation state;
237

    
238
    private FeatureStoreTimeSupport timeSupport;
239

    
240
    private PropertiesSupportHelper propertiesSupportHelper;
241
    private DataTransaction transaction;
242

    
243
    private String editingSessionCode;
244

    
245
    private class StateInformation extends HashMap<Object, Object> {
246

    
247
        private static final long serialVersionUID = 4109026189635185666L;
248

    
249
        private boolean broken;
250
        private Throwable breakingsCause;
251

    
252
        @SuppressWarnings("OverridableMethodCallInConstructor")
253
        public StateInformation() {
254
            this.clear();
255
        }
256

    
257
        @Override
258
        public void clear() {
259
            this.broken = false;
260
            this.breakingsCause = null;
261
            super.clear();
262
        }
263

    
264
        public boolean isBroken() {
265
            return this.broken;
266
        }
267

    
268
        public void broken() {
269
            this.broken = true;
270
        }
271

    
272
        public Throwable getBreakingsCause() {
273
            return this.breakingsCause;
274
        }
275

    
276
        public void setBreakingsCause(Throwable cause) {
277
            if (this.breakingsCause == null) {
278
                this.breakingsCause = cause;
279
            }
280
            this.broken = true;
281
        }
282
    }
283

    
284
    /*
285
     * TODO:
286
     *
287
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
288
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
289
     * featureType al que se le han cambiado las reglas de validacion cuando
290
     * hasStrongChanges=false.
291
     */
292
    public DefaultFeatureStore() {
293
        this.state = new StateInformation();
294
    }
295

    
296
    @Override
297
    protected DataManager getDataManager() {
298
        return this.dataManager;
299
    }
300

    
301
    @Override
302
    public void intialize(DataManager dataManager,
303
            DataStoreParameters parameters) throws InitializeException {
304

    
305
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
306

    
307
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
308
                FeatureStore.METADATA_DEFINITION_NAME,
309
                MetadataManager.METADATA_NAMESPACE
310
        );
311

    
312
        this.dataManager = (DefaultDataManager) dataManager;
313

    
314
        this.parameters = parameters;
315
        this.transforms = new DefaultFeatureStoreTransforms(this);
316
        try {
317
            indexes = new DefaultFeatureIndexes(this);
318
        } catch (DataException e) {
319
            throw new InitializeException(e);
320
        }
321

    
322
    }
323

    
324
    @Override
325
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
326
        this.provider = (FeatureStoreProvider) provider;
327
        this.delegate((DynObject) provider);
328
        this.metadataChildren = new HashSet();
329
        this.metadataChildren.add(provider);
330
        loadDALFile();
331

    
332
        // Habria que crear un metodo en el proveedor para que de prioidad
333
        // a los parametros frente a lo que se a leido en el fichero dal
334
        // DataStoreProvider arreglalo segun los parametros del usuario
335
        // fixFeatureTypeFromParameters
336
        this.provider.fixFeatureTypeFromParameters();
337
        try {
338
            if (defaultFeatureType != null) {
339
                FeatureAttributeDescriptor attrGeom = defaultFeatureType.getDefaultGeometryAttribute();
340
                if (attrGeom != null) {
341
                    DefaultFeatureAttributeDescriptor gattr = (DefaultFeatureAttributeDescriptor) attrGeom;
342
                    IProjection srs = (IProjection) this.getDynValue(METADATA_CRS);
343
                    if (srs != null && srs != gattr.getSRS()) {
344
                        gattr.setSRSForced(srs);
345
                    }
346
                }
347
            }
348
        } catch (Throwable th) {
349
            LOGGER.warn("Can't patch DAL file", th);
350
        }
351
    }
352

    
353
    @Override
354
    public DataStoreParameters getParameters() {
355
        if (this.parameters == null) {
356
            LOGGER.warn("Store parametes are null");
357
        }
358
        return parameters;
359
    }
360

    
361
    @Override
362
    public int getMode() {
363
        return this.mode;
364
    }
365

    
366
    @Override
367
    public DataManager getManager() {
368
        return this.dataManager;
369
    }
370

    
371
    @Override
372
    public UnmodifiableBasicMap<String, DataStore> getChildren() {
373
        UnmodifiableBasicMap<String, DataStore> children = this.provider.getChildren();
374
        if (children == null) {
375
            return UnmodifiableBasicMap.EMPTY_UNMODIFIABLEBASICMAP;
376
        }
377
        return children;
378
    }
379

    
380
    @Override
381
    public FeatureStoreProvider getProvider() {
382
        return this.provider;
383
    }
384

    
385
    public FeatureManager getFeatureManager() {
386
        return this.featureManager;
387
    }
388

    
389
    @Override
390
    public void setFeatureTypes(List types, FeatureType defaultType) {
391
        this.featureTypes = types;
392
        this.defaultFeatureType = defaultType;
393
    }
394

    
395
    public void open() throws OpenException {
396
        if (this.mode != MODE_QUERY) {
397
            // TODO: Se puede hacer un open estando en edicion ?
398
            try {
399
                throw new IllegalStateException();
400
            } catch (Exception ex) {
401
                LOGGER.warn("Opening a store in editing/append mode (" + this.getFullName() + ").", ex);
402
            }
403
        }
404
        if (this.notifyChange(DataStoreNotification.BEFORE_OPEN).isCanceled()) {
405
            return;
406
        }
407
        this.provider.open();
408
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
409
    }
410

    
411
    @Override
412
    public void refresh() throws OpenException, InitializeException {
413
        if (this.mode != MODE_QUERY) {
414
            throw new IllegalStateException();
415
        }
416
        if (this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH).isCanceled()) {
417
            return;
418
        }
419
        if (state.isBroken()) {
420
            this.load(state);
421
        } else {
422
            this.featureCount = null;
423
            this.provider.refresh();
424
        }
425
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
426
    }
427

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

    
445
    @Override
446
    protected void doDispose() throws BaseException {
447
        if (this.mode != MODE_QUERY) {
448
            // TODO: Se puede hacer un dispose estando en edicion ?
449
            try {
450
                throw new IllegalStateException();
451
            } catch (Exception ex) {
452
                LOGGER.warn("Dispossing a store in editing/append mode (" + this.getFullName() + ").", ex);
453
            }
454
        }
455
        if (this.notifyChange(DataStoreNotification.BEFORE_DISPOSE).isCanceled()) {
456
            return;
457
        }
458
        this.disposeIndexes();
459
        if (this.provider != null) {
460
            this.provider.dispose();
461
        }
462
        if (this.selection != null) {
463
            this.selection.dispose();
464
            this.selection = null;
465
        }
466
        this.commands = null;
467
        this.featureCount = null;
468
        if (this.locks != null) {
469
            // this.locks.dispose();
470
            this.locks = null;
471
        }
472

    
473
        if (this.featureTypeManager != null) {
474
            this.featureTypeManager.dispose();
475
            this.featureTypeManager = null;
476
        }
477

    
478
        this.featureManager = null;
479
        this.spatialManager = null;
480

    
481
        this.parameters = null;
482
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
483
        if (delegateObservable != null) {
484
            this.delegateObservable.deleteObservers();
485
            this.delegateObservable = null;
486
        }
487
    }
488

    
489
    @Override
490
    public boolean allowWrite() {
491
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
492
        if (!identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION, this.getParameters(), this.getName())) {
493
            return false;
494
        }
495
        return this.provider.allowWrite();
496
    }
497

    
498
    @Override
499
    public boolean canWriteGeometry(int geometryType) throws DataException {
500
        return this.provider.canWriteGeometry(geometryType, 0);
501
    }
502

    
503
    @Override
504
    public DataServerExplorer getExplorer() throws ReadException,
505
            ValidateDataParametersException {
506
        if (this.state.isBroken()) {
507
            try {
508
                return this.provider.getExplorer();
509
            } catch (Throwable th) {
510
                return null;
511
            }
512
        } else {
513
            return this.provider.getExplorer();
514
        }
515
    }
516

    
517
    /*
518
     * public Metadata getMetadata() throws MetadataNotFoundException {
519
     * // TODO:
520
     * // Si el provider devuelbe null habria que ver de construir aqui
521
     * // los metadatos basicos, como el Envelope y el SRS.
522
     *
523
     * // TODO: Estando en edicion el Envelope deberia de
524
     * // actualizarse usando el spatialManager
525
     * return this.provider.getMetadata();
526
     * }
527
     */
528
    @Override
529
    public Envelope getEnvelope() throws DataException {
530
        if (this.mode == MODE_FULLEDIT) {
531
            // Just in case another thread tries to write in the store
532
            synchronized (this) {
533
                return this.spatialManager.getEnvelope();
534
            }
535
        }
536
        if (hasDynValue(DataStore.METADATA_ENVELOPE)) {
537
            return (Envelope) getDynValue(DataStore.METADATA_ENVELOPE);
538
        }
539
        Envelope envelope = this.provider.getEnvelope();
540
        if (envelope != null) {
541
            return envelope;
542
        }
543
        FeatureAttributeDescriptor attrdesc = this.getDefaultFeatureType().getDefaultGeometryAttribute();
544
        if (attrdesc == null || !attrdesc.isComputed()) {
545
            return null;
546
        }
547
        final int index = attrdesc.getIndex();
548
        final MutableObject<Envelope> envelopeValue = new MutableObject<>();
549
        try {
550
            this.accept((Object obj) -> {
551
                Feature f = (Feature) obj;
552
                Geometry g = (Geometry) f.get(index);
553
                if (g == null) {
554
                    return;
555
                }
556
                if (envelopeValue.getValue() == null) {
557
                    envelopeValue.setValue(g.getEnvelope());
558
                } else {
559
                    envelopeValue.getValue().add(g);
560
                }
561
            });
562
        } catch (Throwable th) {
563
            LOGGER.warn("Can't calculate envelope", th);
564
            return null;
565
        }
566
        return envelopeValue.getValue();
567
    }
568

    
569
    /**
570
     * @throws org.gvsig.fmap.dal.exception.DataException
571
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
572
     */
573
    @Override
574
    public IProjection getSRSDefaultGeometry() throws DataException {
575
        return this.getDefaultFeatureType().getDefaultSRS();
576
    }
577

    
578
    @Override
579
    public FeatureSelection createDefaultFeatureSelection()
580
            throws DataException {
581
        return new DefaultFeatureSelection(this);
582
    }
583

    
584
    @Override
585
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
586
            throws DataException {
587
        if (type.hasOID()) {
588
            return new DefaultFeatureProvider(type,
589
                    this.provider.createNewOID());
590
        }
591
        return new DefaultFeatureProvider(type);
592
    }
593

    
594
    @Override
595
    public void saveToState(PersistentState state) throws PersistenceException {
596
        /*if (this.mode != FeatureStore.MODE_QUERY) {
597
            throw new PersistenceException(new IllegalStateException(
598
                this.getName()));
599
        }*/
600
        state.set("dataStoreName", this.getName());
601
        state.set("parameters", this.parameters);
602
        state.set("selection", this.selection);
603
        state.set("transforms", this.transforms);
604
        // TODO locks persistence
605
        // state.set("locks", this.locks);
606
        // TODO indexes persistence
607
        // state.set("indexes", this.indexes);
608
        Map evaluatedAttr = new HashMap(1);
609
        Iterator iterType = featureTypes.iterator();
610
        Iterator iterAttr;
611
        FeatureType type;
612
        DefaultFeatureAttributeDescriptor attr;
613
        List attrs;
614
        while (iterType.hasNext()) {
615
            type = (FeatureType) iterType.next();
616
            attrs = new ArrayList();
617
            iterAttr = type.iterator();
618
            while (iterAttr.hasNext()) {
619
                attr = (DefaultFeatureAttributeDescriptor) iterAttr.next();
620
                if ((attr.getEvaluator() != null)
621
                        && (attr.getEvaluator() instanceof Persistent)) {
622
                    attrs.add(attr);
623
                }
624
            }
625
            if (!attrs.isEmpty()) {
626
                evaluatedAttr.put(type.getId(), attrs);
627
            }
628

    
629
        }
630

    
631
        if (evaluatedAttr.isEmpty()) {
632
            evaluatedAttr = null;
633
        }
634

    
635
        state.set("evaluatedAttributes", evaluatedAttr);
636
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
637

    
638
    }
639

    
640
    @Override
641
    public void loadFromState(final PersistentState persistentState)
642
            throws PersistenceException {
643
        if (this.provider != null) {
644
            throw new PersistenceStoreAlreadyLoadedException(this.getName());
645
        }
646
        if (this.getManager() == null) {
647
            this.dataManager = (DefaultDataManager) DALLocator.getDataManager();
648
        }
649
        state.clear();
650
        try {
651
            state.put("parameters", persistentState.get("parameters"));
652
        } catch (Throwable th) {
653
            state.setBreakingsCause(th);
654
        }
655
        try {
656
            state.put("selection", persistentState.get("selection"));
657
        } catch (Throwable th) {
658
            state.setBreakingsCause(th);
659
        }
660
        try {
661
            state.put("transforms", persistentState.get("transforms"));
662
        } catch (Throwable th) {
663
            state.setBreakingsCause(th);
664
        }
665
        try {
666
            state.put("evaluatedAttributes", persistentState.get("evaluatedAttributes"));
667
        } catch (Throwable th) {
668
            state.setBreakingsCause(th);
669
        }
670
        try {
671
            state.put("defaultFeatureTypeId", persistentState.getString("defaultFeatureTypeId"));
672
        } catch (Throwable th) {
673
            state.setBreakingsCause(th);
674
        }
675
        load(state);
676
        ((DefaultDataManager) this.getDataManager()).addObservers(this);
677
    }
678

    
679
    private void load(StateInformation state) {
680
        this.featureTypes = new ArrayList();
681
        this.defaultFeatureType = null;
682
        this.featureCount = null;
683

    
684
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
685
        try {
686
            intialize(dataManager, params);
687
        } catch (Throwable th) {
688
            state.setBreakingsCause(th);
689
        }
690

    
691
        try {
692
            DataStoreProvider prov = dataManager.createProvider(
693
                    getStoreProviderServices(),
694
                    params
695
            );
696
            setProvider(prov);
697
        } catch (Throwable th) {
698
            LOGGER.warn("Can't load store from state.", th);
699
            state.setBreakingsCause(th);
700
        }
701
        try {
702
            selection = (FeatureSelection) state.get("selection");
703
        } catch (Throwable th) {
704
            state.setBreakingsCause(th);
705
        }
706

    
707
        try {
708
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
709
            this.transforms.setFeatureStore(this);
710
            for (FeatureStoreTransform transform : this.transforms) {
711
                try {
712
                    transform.setUp();
713
                } catch (Throwable th) {
714
                    state.setBreakingsCause(th);
715
                }
716
            }
717
        } catch (Throwable th) {
718
            state.setBreakingsCause(th);
719
        }
720

    
721
        try {
722
            Map evaluatedAttributes = (Map) state.get("evaluatedAttributes");
723
            if ((evaluatedAttributes != null) && !evaluatedAttributes.isEmpty()) {
724
                Iterator iterEntries = evaluatedAttributes.entrySet().iterator();
725
                while (iterEntries.hasNext()) {
726
                    Entry entry = (Entry) iterEntries.next();
727
                    List attrs = (List) entry.getValue();
728
                    if (attrs.isEmpty()) {
729
                        continue;
730
                    }
731
                    int fTypePos = -1;
732
                    DefaultFeatureType type = null;
733
                    for (int i = 0; i < featureTypes.size(); i++) {
734
                        type = (DefaultFeatureType) featureTypes.get(i);
735
                        if (type.getId().equals(entry.getKey())) {
736
                            fTypePos = i;
737
                            break;
738
                        }
739
                    }
740
                    if (type == null) {
741
                        throw new PersistenceCantFindFeatureTypeException(
742
                                getName(), (String) entry.getKey());
743
                    }
744
                    DefaultEditableFeatureType eType = (DefaultEditableFeatureType) type.getEditable();
745
                    Iterator<FeatureAttributeDescriptor> iterAttr = attrs.iterator();
746
                    while (iterAttr.hasNext()) {
747
                        FeatureAttributeDescriptor attr = iterAttr.next();
748
                        eType.addLike(attr);
749
                    }
750
                    featureTypes.set(fTypePos, eType.getNotEditableCopy());
751

    
752
                }
753

    
754
            }
755
        } catch (Throwable th) {
756
            state.setBreakingsCause(th);
757
        }
758

    
759
        try {
760
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
761
            FeatureType ftype;
762

    
763
            if (defaultFeatureType == null
764
                    || defaultFeatureType.getId() == null
765
                    || !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
766

    
767
                ftype = getFeatureType(defaultFeatureTypeId);
768
                if (ftype == null) {
769
                    /*
770
                             * Un error en el m?todo de PostgreSQL getName(), hace que
771
                             * el nombre del featureType sea valor retornado por el getProviderName()
772
                             * De momento se pone este parche para apa?arlo y poder mantener compatibilidad
773
                             * con proyectos antiguos (2.1 y 2.2)
774
                     */
775
                    ftype = getFeatureType(getName());
776
                    if (ftype == null) {
777
                        throw new RuntimeException("Can't locate feature type");
778
                    }
779
                }
780
                defaultFeatureType = ftype;
781
            }
782
        } catch (Throwable th) {
783
            state.setBreakingsCause(th);
784
        }
785

    
786
        LOGGER.debug("load() broken:{}, {}, {}.",
787
                new Object[]{state.isBroken(), this.getProviderName(), params}
788
        );
789
    }
790

    
791
    public DataStoreProviderServices getStoreProviderServices() {
792
        return this;
793
    }
794

    
795
    public static void registerPersistenceDefinition() {
796
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
797
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
798
            DynStruct definition
799
                    = manager.addDefinition(DefaultFeatureStore.class,
800
                            PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
801
                            + " Persistent definition", null, null);
802
            definition.addDynFieldString("dataStoreName").setMandatory(true)
803
                    .setPersistent(true);
804

    
805
            definition.addDynFieldObject("parameters")
806
                    .setClassOfValue(DynObject.class).setMandatory(true)
807
                    .setPersistent(true);
808

    
809
            definition.addDynFieldObject("selection")
810
                    .setClassOfValue(FeatureSelection.class).setMandatory(false)
811
                    .setPersistent(true);
812

    
813
            definition.addDynFieldObject("transforms")
814
                    .setClassOfValue(DefaultFeatureStoreTransforms.class)
815
                    .setMandatory(true).setPersistent(true);
816

    
817
            definition.addDynFieldMap("evaluatedAttributes")
818
                    .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
819
                    .setMandatory(false).setPersistent(true);
820

    
821
            definition.addDynFieldString("defaultFeatureTypeId")
822
                    .setMandatory(true).setPersistent(true);
823
        }
824
    }
825

    
826
    public static void registerMetadataDefinition() throws MetadataException {
827
        MetadataManager manager = MetadataLocator.getMetadataManager();
828
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
829
            DynStruct metadataDefinition
830
                    = manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
831
            metadataDefinition.extend(manager
832
                    .getDefinition(DataStore.METADATA_DEFINITION_NAME));
833
        }
834
    }
835

    
836
    //
837
    // ====================================================================
838
    // Gestion de la seleccion
839
    //
840
    @Override
841
    public void setSelection(DataSet selection) throws DataException {
842
        this.setSelection((FeatureSet) selection);
843
    }
844

    
845
    @Override
846
    public DataSet createSelection() throws DataException {
847
        return createFeatureSelection();
848
    }
849

    
850
    @Override
851
    public DataSet getSelection() throws DataException {
852
        return this.getFeatureSelection();
853
    }
854

    
855
    @Override
856
    public void setSelection(FeatureSet selection) throws DataException {
857
        setSelection(selection, true);
858
    }
859

    
860
    public void setSelection(FeatureSet selection, boolean undoable)
861
            throws DataException {
862
        if (selection == null) {
863
            if (undoable) {
864
                throw new SelectionNotAllowedException(getName());
865
            }
866

    
867
        } else {
868
            if (selection.equals(this.selection)) {
869
                return;
870
            }
871
            if (!selection.isFromStore(this)) {
872
                throw new SelectionNotAllowedException(getName());
873
            }
874
        }
875

    
876
        if (this.selection != null) {
877
            this.selection.deleteObserver(this);
878
        }
879
        if (selection == null) {
880
            if (this.selection != null) {
881
                this.selection.dispose();
882
            }
883
            this.selection = null;
884
            return;
885
        }
886
        if (selection instanceof FeatureSelection) {
887
            if (undoable && isEditing()) {
888
                commands.selectionSet(this, this.selection,
889
                        (FeatureSelection) selection);
890
            }
891
            if (this.selection != null) {
892
                this.selection.dispose();
893
            }
894
            this.selection = (FeatureSelection) selection;
895
        } else {
896
            if (undoable && isEditing()) {
897
                commands.startComplex("_selectionSet");
898
            }
899
            if (selection instanceof DefaultFeatureSelection) {
900
                DefaultFeatureSelection defSelection
901
                        = (DefaultFeatureSelection) selection;
902
                defSelection.deselectAll(undoable);
903
                defSelection.select(selection, undoable);
904
            } else {
905
                this.selection.deselectAll();
906
                this.selection.select(selection);
907
            }
908
            if (undoable && isEditing()) {
909
                commands.endComplex();
910
            }
911
        }
912
        this.selection.addObserver(this);
913

    
914
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
915
    }
916

    
917
    @Override
918
    public FeatureSelection createFeatureSelection() throws DataException {
919
        long maxSize = dataManager.getMaxSizeForSmallFeatureSelection();
920
        if (this.provider.getFeatureCount() > maxSize) {
921
            return createLargeFeatureSelection();
922
        }
923
        return this.provider.createFeatureSelection();
924
    }
925

    
926
    @Override
927
    public FeatureSelection createLargeFeatureSelection() throws DataException {
928
        return new LargeFeatureSelection(this);
929

    
930
    }
931

    
932
    @Override
933
    public FeatureSelection createMemoryFeatureSelection() throws DataException {
934
        return this.provider.createFeatureSelection();
935
    }
936

    
937
    @Override
938
    public FeatureSelection getFeatureSelection() throws DataException {
939
        if (selection == null) {
940
            this.selection = createFeatureSelection();
941
            this.selection.addObserver(this);
942
        }
943
        return selection;
944
    }
945

    
946
    //
947
    // ====================================================================
948
    // Gestion de notificaciones
949
    //
950
    @Override
951
    public FeatureStoreNotification notifyChange(FeatureStoreNotification storeNotification) {
952
        if (delegateObservable != null) {
953
            try {
954
                delegateObservable.notifyObservers(storeNotification);
955
            } catch (Throwable ex) {
956
                LOGGER.warn("Problems notifying changes in the store '" + this.getName() + " (" + storeNotification.getType() + ").", ex);
957
            }
958
        }
959
        return storeNotification;
960
    }
961

    
962
    @Override
963
    public FeatureStoreNotification notifyChange(String notification) {
964
        return notifyChange(new DefaultFeatureStoreNotification(this, notification));
965
    }
966

    
967
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode) {
968
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode));
969
    }
970

    
971
    public FeatureStoreNotification notifyChange(String notification, String editingSessionCode, int editMode) {
972
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode, editMode));
973
    }
974

    
975
    public FeatureStoreNotification notifyChange(String notification,
976
            String editingSessionCode,
977
            Iterator<FeatureReference> deleteds,
978
            Iterator<EditableFeature> inserteds,
979
            Iterator<EditableFeature> updateds,
980
            Iterator<FeatureTypeChanged> featureTypesChanged,
981
            boolean isSelectionCompromised) {
982
        return notifyChange(new DefaultFeatureStoreNotification(this, notification, editingSessionCode,
983
                deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised));
984
    }
985

    
986
    @Override
987
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
988
        Feature f = null;
989
        if (data != null) {
990
            try {
991
                f = createFeature(data);
992
            } catch (Throwable ex) {
993
                LOGGER.warn("Problems creating a feature to notifying changes in the store '" + this.getName() + " (" + notification + ").", ex);
994
            }
995
        }
996
        return notifyChange(notification, f);
997
    }
998

    
999
    public FeatureStoreNotification notifyChange(String notification, Feature feature) {
1000
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
1001
                feature));
1002
    }
1003

    
1004
    public FeatureStoreNotification notifyChange(String notification, Command command) {
1005
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
1006
                command));
1007
    }
1008

    
1009
    public FeatureStoreNotification notifyChange(String notification, EditableFeatureType type) {
1010
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
1011
                type));
1012
    }
1013

    
1014
    @Override
1015
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
1016
        return notifyChange(new DefaultFeatureStoreNotification(this,
1017
                DataStoreNotification.RESOURCE_CHANGED));
1018
    }
1019

    
1020
    //
1021
    // ====================================================================
1022
    // Gestion de bloqueos
1023
    //
1024
    @Override
1025
    public boolean isLocksSupported() {
1026
        return this.provider.isLocksSupported();
1027
    }
1028

    
1029
    @Override
1030
    public FeatureLocks getLocks() throws DataException {
1031
        if (!this.provider.isLocksSupported()) {
1032
            LOGGER.warn("Locks not supported");
1033
            return null;
1034
        }
1035
        if (locks == null) {
1036
            this.locks = this.provider.createFeatureLocks();
1037
        }
1038
        return locks;
1039
    }
1040

    
1041
    //
1042
    // ====================================================================
1043
    // Interface Observable
1044
    //
1045
    @Override
1046
    public void disableNotifications() {
1047
        this.delegateObservable.disableNotifications();
1048

    
1049
    }
1050

    
1051
    @Override
1052
    public void enableNotifications() {
1053
        this.delegateObservable.enableNotifications();
1054
    }
1055

    
1056
    @Override
1057
    public void beginComplexNotification() {
1058
        this.delegateObservable.beginComplexNotification();
1059

    
1060
    }
1061

    
1062
    @Override
1063
    public void endComplexNotification() {
1064
        this.delegateObservable.endComplexNotification();
1065

    
1066
    }
1067

    
1068
    @Override
1069
    public void addObserver(Observer observer) {
1070
        if (delegateObservable != null) {
1071
            this.delegateObservable.addObserver(observer);
1072
        }
1073
    }
1074

    
1075
    @Override
1076
    public void deleteObserver(Observer observer) {
1077
        if (delegateObservable != null) {
1078
            this.delegateObservable.deleteObserver(observer);
1079
        }
1080
    }
1081

    
1082
    @Override
1083
    public void deleteObservers() {
1084
        this.delegateObservable.deleteObservers();
1085

    
1086
    }
1087

    
1088
    //
1089
    // ====================================================================
1090
    // Interface Observer
1091
    //
1092
    // Usado para observar:
1093
    // - su seleccion
1094
    // - sus bloqueos
1095
    // - sus recursos
1096
    //
1097
    @Override
1098
    public void update(Observable observable, Object notification) {
1099
        if (observable instanceof FeatureSet) {
1100
            if (observable == this.selection) {
1101
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1102
            } else if (observable == this.locks) {
1103
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1104
            }
1105

    
1106
        } else if (observable instanceof FeatureStoreProvider) {
1107
            if (observable == this.provider) {
1108

    
1109
            }
1110
        } else if (observable instanceof FeatureReferenceSelection) {
1111
            if (notification instanceof String) {
1112
                this.notifyChange((String) notification);
1113
            }
1114
        }
1115
    }
1116

    
1117
    //
1118
    // ====================================================================
1119
    // Edicion
1120
    //
1121
    private void newVersionOfUpdate() {
1122
        this.versionOfUpdate++;
1123
    }
1124

    
1125
    private long currentVersionOfUpdate() {
1126
        return this.versionOfUpdate;
1127
    }
1128

    
1129
    private void checkInEditingMode() throws NeedEditingModeException {
1130
        if (mode != MODE_FULLEDIT) {
1131
            throw new NeedEditingModeException(this.getName());
1132
        }
1133
    }
1134

    
1135
    private void checkNotInAppendMode() throws IllegalStateException {
1136
        if (mode == MODE_APPEND) {
1137
            throw new IllegalStateException("Error: store "
1138
                    + this.getFullName() + " is in append mode");
1139
        }
1140
    }
1141

    
1142
    private void checkIsOwnFeature(Feature feature)
1143
            throws IllegalFeatureException {
1144
        if (((DefaultFeature) feature).getStore() != this) {
1145
            throw new IllegalFeatureException(this.getName());
1146
        }
1147
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1148
        // fixFeatureType((DefaultFeatureType) feature.getType());
1149
    }
1150

    
1151
    private void exitEditingMode() {
1152
        if (commands != null) {
1153
            try {
1154
                commands.clear();
1155
            } catch (Exception ex) {
1156
                LOGGER.trace("Can't clear commands", ex);
1157
            }
1158
            commands = null;
1159
        }
1160

    
1161
        if (featureTypeManager != null) {
1162
            DisposeUtils.disposeQuietly(featureTypeManager);
1163
            featureTypeManager = null;
1164

    
1165
        }
1166

    
1167
        // TODO implementar un dispose para estos dos
1168
        featureManager = null;
1169
        spatialManager = null;
1170

    
1171
        featureCount = null;
1172

    
1173
        mode = MODE_QUERY;
1174
        hasStrongChanges = true; // Lo deja a true por si las moscas
1175
        hasInserts = true;
1176

    
1177
        this.editingSessionCode = null;
1178
    }
1179

    
1180
    @Override
1181
    synchronized public void edit() throws DataException {
1182
        edit(MODE_FULLEDIT);
1183
    }
1184

    
1185
    @Override
1186
    synchronized public void edit(int mode) throws DataException {
1187
        LOGGER.debug("Starting editing in mode: {}", mode);
1188
        String newSessionCode = this.createUniqueID();
1189
        try {
1190
            if (this.mode != MODE_QUERY) {
1191
                throw new AlreadyEditingException(this.getName());
1192
            }
1193
            if (!this.provider.supportsAppendMode()) {
1194
                mode = MODE_FULLEDIT;
1195
            }
1196
            switch (mode) {
1197
                case MODE_QUERY:
1198
                    throw new IllegalStateException(this.getName());
1199

    
1200
                case MODE_FULLEDIT:
1201
                    if (!this.transforms.isEmpty()) {
1202
                        throw new IllegalStateException(this.getName());
1203
                    }
1204
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1205
                            newSessionCode, mode).isCanceled()) {
1206
                        return;
1207
                    }
1208
                    this.editingSessionCode = newSessionCode;
1209
                    invalidateIndexes();
1210
                    featureManager = new FeatureManager(this);
1211
                    featureTypeManager = new FeatureTypeManager(this);
1212
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
1213

    
1214
                    commands = new DefaultFeatureCommandsStack(
1215
                            this, featureManager,
1216
                            spatialManager, featureTypeManager);
1217
                    this.mode = MODE_FULLEDIT;
1218
                    hasStrongChanges = false;
1219
                    hasInserts = false;
1220
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING, newSessionCode, this.mode);
1221
                    break;
1222

    
1223
                case MODE_APPEND:
1224
                    if (!this.transforms.isEmpty()) {
1225
                        throw new IllegalStateException(this.getName());
1226
                    }
1227
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1228
                            newSessionCode, mode).isCanceled()) {
1229
                        return;
1230
                    }
1231
                    this.editingSessionCode = newSessionCode;
1232
                    invalidateIndexes();
1233
                    this.provider.beginAppend();
1234
                    this.mode = MODE_APPEND;
1235
                    hasInserts = false;
1236
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1237
                            newSessionCode, this.mode);
1238
                    break;
1239
                case MODE_PASS_THROUGH:
1240
                    if (!this.provider.supportsPassThroughMode()) {
1241
                        throw new IllegalStateException(this.getName());
1242
                    }
1243
                    if (!this.transforms.isEmpty()) {
1244
                        throw new IllegalStateException(this.getName());
1245
                    }
1246
                    if (notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING,
1247
                            newSessionCode, mode).isCanceled()) {
1248
                        return;
1249
                    }
1250
                    this.editingSessionCode = newSessionCode;
1251
                    invalidateIndexes();
1252
                    this.mode = MODE_PASS_THROUGH;
1253
                    hasInserts = false;
1254
                    notifyChange(FeatureStoreNotification.AFTER_STARTEDITING,
1255
                            newSessionCode, this.mode);
1256
                    break;
1257

    
1258
            }
1259
        } catch (Exception e) {
1260
            try {
1261
                if (this.mode != MODE_QUERY) {
1262
                    exitEditingMode();
1263
                }
1264
                notifyChange(FeatureStoreNotification.FAILED_STARTEDITING,
1265
                        newSessionCode, mode);
1266
            } catch (Throwable th) {
1267
                LOGGER.warn("Can't cleanup after error in start editing.", th);
1268
            }
1269
            throw new StoreEditException(e, this.getName());
1270
        }
1271
    }
1272

    
1273
    private void invalidateIndexes() {
1274
        setIndexesValidStatus(false);
1275
    }
1276

    
1277
    private void setIndexesValidStatus(boolean valid) {
1278
        FeatureIndexes theIndexes = getIndexes();
1279
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1280
                ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1281
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1282
            FeatureIndex index = (FeatureIndex) iterator.next();
1283
            if (index instanceof FeatureIndexProviderServices) {
1284
                FeatureIndexProviderServices indexServices
1285
                        = (FeatureIndexProviderServices) index;
1286
                indexServices.setValid(valid);
1287
            }
1288
        }
1289
    }
1290

    
1291
    private void updateIndexes() throws FeatureIndexException {
1292
        FeatureIndexes theIndexes = getIndexes();
1293
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1294
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1295
            FeatureIndex index = (FeatureIndex) iterator.next();
1296
            if (index instanceof FeatureIndexProviderServices) {
1297
                FeatureIndexProviderServices indexServices
1298
                        = (FeatureIndexProviderServices) index;
1299
                indexServices.fill(true, null);
1300
            }
1301
        }
1302
    }
1303

    
1304
    private void waitForIndexes() {
1305
        FeatureIndexes theIndexes = getIndexes();
1306
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1307
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1308
            FeatureIndex index = (FeatureIndex) iterator.next();
1309
            if (index instanceof FeatureIndexProviderServices) {
1310
                FeatureIndexProviderServices indexServices
1311
                        = (FeatureIndexProviderServices) index;
1312
                indexServices.waitForIndex();
1313
            }
1314
        }
1315
    }
1316

    
1317
    private void disposeIndexes() {
1318
        FeatureIndexes theIndexes = getIndexes();
1319
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1320
        if (theIndexes == null) {
1321
            return;
1322
        }
1323
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1324
            FeatureIndex index = (FeatureIndex) iterator.next();
1325
            if (index instanceof FeatureIndexProviderServices) {
1326
                FeatureIndexProviderServices indexServices
1327
                        = (FeatureIndexProviderServices) index;
1328
                indexServices.dispose();
1329
            }
1330
        }
1331
    }
1332

    
1333
    @Override
1334
    public boolean isEditing() {
1335
        return mode == MODE_FULLEDIT;
1336
    }
1337

    
1338
    @Override
1339
    public boolean isAppending() {
1340
        return mode == MODE_APPEND;
1341
    }
1342

    
1343
    @Override
1344
    synchronized public void update(EditableFeatureType type)
1345
            throws DataException {
1346
        try {
1347
            if (type == null) {
1348
                throw new NullFeatureTypeException(getName());
1349
            }
1350

    
1351
            switch (this.mode) {
1352
                case MODE_QUERY:
1353
                    if (type.hasOnlyMetadataChanges(this.defaultFeatureType)) {
1354
                        if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1355
                            return;
1356
                        }
1357
                        FeatureType theType = type.getNotEditableCopy();
1358
                        if (defaultFeatureType.getId().equals(theType.getId())) {
1359
                            defaultFeatureType = theType;
1360
                        }
1361
                        List newtypes = new ArrayList();
1362
                        for (FeatureType featureType : this.featureTypes) {
1363
                            if (featureType.getId().equals(theType.getId())) {
1364
                                newtypes.add(theType);
1365
                            } else {
1366
                                newtypes.add(featureType);
1367
                            }
1368
                        }
1369
                        this.featureTypes = newtypes;
1370
                        saveDALFile();
1371
                        notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1372
                    }
1373

    
1374
                    break;
1375
                case MODE_FULLEDIT:
1376
                    if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled()) {
1377
                        return;
1378
                    }
1379
                    newVersionOfUpdate();
1380

    
1381
                    FeatureType oldt = type.getSource().getCopy();
1382
                    FeatureType newt = type.getCopy();
1383
                    commands.update(newt, oldt);
1384
                    hasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1385
                    notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1386
                    break;
1387
                case MODE_APPEND:
1388
                case MODE_PASS_THROUGH:
1389
                    throw new NeedEditingModeException(this.getName());
1390

    
1391
            }
1392
        } catch (Exception e) {
1393
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1394
        }
1395
    }
1396

    
1397
    @Override
1398
    public void delete(Feature feature) throws DataException {
1399
        switch (this.mode) {
1400
            case MODE_PASS_THROUGH:
1401
                checkIsOwnFeature(feature);
1402
                if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1403
                    return;
1404
                }
1405
                this.provider.passThroughDelete((FeatureReferenceProviderServices) feature.getReference());
1406
                notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1407
                break;
1408
            default:
1409
                this.commands.delete(feature);
1410
                break;
1411

    
1412
        }
1413
    }
1414

    
1415
    @Override
1416
    public void delete(String filter) {
1417
        if (StringUtils.isBlank(filter)) {
1418
            return;
1419
        }
1420
        this.delete(ExpressionUtils.createExpression(filter));
1421
    }
1422

    
1423
    @Override
1424
    public void delete(Expression filter) {
1425
        // TODO: Optimizar pasandolo directamente al proveedor si no estamos en edicion y lo soporta.
1426
        if (filter == null) {
1427
            return;
1428
        }
1429
        boolean pendingFinishEditing = false;
1430
        DisposableFeatureSetIterable features = null;
1431
        try {
1432
            switch (this.mode) {
1433
                case MODE_QUERY:
1434
                    pendingFinishEditing = true;
1435
                    this.edit();
1436
                    break;
1437
                case MODE_APPEND:
1438
                    throw new IllegalStateException("Delete not allowed in append mode.");
1439
                case MODE_FULLEDIT:
1440
                    break;
1441
                case MODE_PASS_THROUGH:
1442
//                    this.provider.passThroughDelete(filter);
1443
//                    return;
1444
                    break;
1445
                default:
1446
                    throw new IllegalStateException("Mode " + this.mode + " not supported.");
1447
            }
1448

    
1449
            FeatureSet fset = this.getFeatureSet(filter);
1450
            features = fset.iterable();
1451
            for (Feature f : features) {
1452
                fset.delete(f);
1453
            }
1454
        } catch (DataException ex) {
1455
            throw new DataRuntimeException(ex.getFormatString(), ex.getMessageKey(), ex.getCode()) {
1456
            };
1457
        } catch (Exception ex) {
1458
            throw new RuntimeException("Can't delete features (" + filter.getPhrase() + ").", ex);
1459
        } finally {
1460
            if (pendingFinishEditing) {
1461
                this.finishEditingQuietly();
1462
            }
1463
            DisposeUtils.disposeQuietly(features);
1464
        }
1465
    }
1466

    
1467
    synchronized public void doDelete(Feature feature) throws DataException {
1468
        if (feature == null) {
1469
            throw new IllegalArgumentException("feature argument can't be null.");
1470
        }
1471
        try {
1472
            checkInEditingMode();
1473
            checkIsOwnFeature(feature);
1474
            if (feature instanceof EditableFeature && !((EditableFeature)feature).isUpdatable()) {
1475
                //La feature no est? persistida en disco
1476
                throw new StoreDeleteEditableFeatureException(getName());
1477
            }
1478
            if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1479
                return;
1480
            }
1481

    
1482
            //Update the featureManager and the spatialManager
1483
            featureManager.delete(feature);
1484
            spatialManager.deleteFeature(feature);
1485

    
1486
            newVersionOfUpdate();
1487
            hasStrongChanges = true;
1488
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1489
        } catch (Exception e) {
1490
            throw new StoreDeleteFeatureException(e, this.getName());
1491
        }
1492
    }
1493

    
1494
    @Override
1495
    public synchronized void insert(FeatureSet set) throws DataException {
1496
        switch (mode) {
1497
            case MODE_QUERY:
1498
                throw new NeedEditingModeException(this.getName());
1499

    
1500
            case MODE_APPEND:
1501
            case MODE_FULLEDIT:
1502
            case MODE_PASS_THROUGH:
1503
            try {
1504
                set.accept((Object obj) -> {
1505
                    EditableFeature ef = createNewFeature((Feature) obj);
1506
                    insert(ef);
1507
                });
1508
            } catch (BaseException ex) {
1509
                throw new StoreInsertFeatureException(ex, this.getName());
1510
            }
1511
            break;
1512
        }
1513
    }
1514

    
1515
    private static EditableFeature lastChangedFeature = null;
1516

    
1517
    @Override
1518
    public synchronized void insert(EditableFeature feature)
1519
            throws DataException {
1520
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1521
        try {
1522
            switch (mode) {
1523
                case MODE_QUERY:
1524
                    throw new NeedEditingModeException(this.getName());
1525

    
1526
                case MODE_APPEND:
1527
                    checkIsOwnFeature(feature);
1528
                    if (feature.isUpdatable()) {
1529
                        throw new NoNewFeatureInsertException(this.getName());
1530
                    }
1531
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1532
                        return;
1533
                    }
1534
                    this.featureCount = null;
1535
                    feature.validate(CHECK_RULES_AT_EDITING);
1536
                    provider.append(((DefaultEditableFeature) feature).getData());
1537
                    hasStrongChanges = true;
1538
                    hasInserts = true;
1539
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1540
                    break;
1541

    
1542
                case MODE_FULLEDIT:
1543
                    if (feature.isUpdatable()) {
1544
                        throw new NoNewFeatureInsertException(this.getName());
1545
                    }
1546
                    feature.validate(CHECK_RULES_AT_EDITING);
1547
                    commands.insert(feature);
1548
                    break;
1549

    
1550
                case MODE_PASS_THROUGH:
1551
                    checkIsOwnFeature(feature);
1552
                    if (feature.isUpdatable()) {
1553
                        throw new NoNewFeatureInsertException(this.getName());
1554
                    }
1555
                    if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1556
                        return;
1557
                    }
1558
                    feature.validate(CHECK_RULES_AT_EDITING);
1559
                    this.provider.passThroughInsert(((DefaultEditableFeature) feature).getData());
1560
                    notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1561
                    break;
1562
            }
1563
        } catch (Exception e) {
1564
            throw new StoreInsertFeatureException(e, this.getName());
1565
        }
1566
    }
1567

    
1568
    synchronized public void doInsert(EditableFeature feature)
1569
            throws DataException {
1570
        checkIsOwnFeature(feature);
1571

    
1572
        waitForIndexes();
1573

    
1574
        if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1575
            return;
1576
        }
1577
        newVersionOfUpdate();
1578
        if ((lastChangedFeature == null)
1579
                || (lastChangedFeature.getSource() != feature.getSource())) {
1580
            lastChangedFeature = feature;
1581
            feature.validate(CHECK_RULES_AT_EDITING);
1582
            lastChangedFeature = null;
1583
        }
1584
        //Update the featureManager and the spatialManager
1585
        ((DefaultFeature) feature).setInserted(true);
1586
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1587

    
1588
        featureManager.add(feature);
1589
        spatialManager.insertFeature(newFeature);
1590

    
1591
        hasStrongChanges = true;
1592
        hasInserts = true;
1593
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1594
    }
1595

    
1596
    @Override
1597
    public void update(EditableFeature feature)
1598
            throws DataException {
1599
        switch (this.mode) {
1600
            case MODE_PASS_THROUGH:
1601
                checkIsOwnFeature(feature);
1602
                if (!feature.isUpdatable()) {
1603
                    throw new NoNewFeatureInsertException(this.getName());
1604
                }
1605
                if (notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled()) {
1606
                    return;
1607
                }
1608
                feature.validate(CHECK_RULES_AT_EDITING);
1609
                this.provider.passThroughUpdate(((DefaultEditableFeature) feature).getData());
1610
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1611
                break;
1612
            case MODE_FULLEDIT:
1613
                if (feature.isUpdatable()) {
1614
                    commands.update(feature, feature.getSource());
1615
                    return;
1616
                }
1617
                // FIXME: Deberiamos lanzar aqui un error en lugar de hacer el insert.
1618
                //        O lanzar un mensaje al log?
1619
                insert(feature);
1620
                break;
1621
            default:
1622
                throw new NeedEditingModeException(this.getName());
1623
        }
1624
    }
1625

    
1626
    @Override
1627
    public void update(Object... parameters) throws DataException {
1628
        if (parameters.length == 1) {
1629
            Object param0 = parameters[0];
1630
            if (param0 instanceof EditableFeature) {
1631
                this.update((EditableFeature) param0);
1632
            } else if (param0 instanceof EditableFeatureType) {
1633
                this.update((EditableFeatureType) param0);
1634
            } else {
1635
                throw new IllegalArgumentException("Type of first parameter isn't supported");
1636
            }
1637
            return;
1638
        }
1639

    
1640
        Expression filter = null;
1641
        long end = parameters.length;
1642
        if (parameters.length % 2 == 1) { //IMPAR
1643
            Object param = parameters[parameters.length - 1];
1644
            if (param != null) {
1645
                if (param instanceof Expression) {
1646
                    filter = (Expression) param;
1647
                } else {
1648
                    filter = ExpressionUtils.createExpression(param.toString());
1649
                }
1650
            }
1651
        } else {
1652
            end = parameters.length - 1;
1653
        }
1654

    
1655
        switch (this.mode) {
1656
            case MODE_PASS_THROUGH:
1657
                this.provider.passThroughUpdate(
1658
                        //                    this.getName(), 
1659
                        parameters,
1660
                        filter);
1661
                break;
1662
            case MODE_FULLEDIT:
1663
                FeatureSet set = this.getFeatureSet(filter);
1664
                DisposableIterator it = set.fastIterator();
1665
                while (it.hasNext()) {
1666
                    Feature feature = (Feature) it.next();
1667
                    EditableFeature ef = feature.getEditable();
1668
                    for (int i = 0; i < end; i += 2) {
1669
                        String name = (String) parameters[i];
1670
                        Object value = parameters[i + 1];
1671
                        ef.set(name, value);
1672
                    }
1673
                    set.update(ef);
1674
                }
1675
                DisposeUtils.disposeQuietly(it);
1676
                DisposeUtils.disposeQuietly(set);
1677
                break;
1678
            default:
1679
                throw new NeedEditingModeException(this.getName());
1680
        }
1681
    }
1682

    
1683
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1684
            throws DataException {
1685
        try {
1686
            checkInEditingMode();
1687
            checkIsOwnFeature(feature);
1688
            if (notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled()) {
1689
                return;
1690
            }
1691
            newVersionOfUpdate();
1692
            if ((lastChangedFeature == null)
1693
                    || (lastChangedFeature.getSource() != feature.getSource())) {
1694
                lastChangedFeature = feature;
1695
                feature.validate(CHECK_RULES_AT_EDITING);
1696
                lastChangedFeature = null;
1697
            }
1698

    
1699
            //Update the featureManager and the spatialManager
1700
            Feature newf = feature.getNotEditableCopy();
1701
            featureManager.update(feature, oldFeature);
1702
            spatialManager.updateFeature(newf, oldFeature);
1703

    
1704
            hasStrongChanges = true;
1705
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1706
        } catch (Exception e) {
1707
            throw new StoreUpdateFeatureException(e, this.getName());
1708
        }
1709
    }
1710

    
1711
    @Override
1712
    synchronized public void redo() throws RedoException {
1713
        Command redo = commands.getNextRedoCommand();
1714
        try {
1715
            checkInEditingMode();
1716
        } catch (NeedEditingModeException ex) {
1717
            throw new RedoException(redo, ex);
1718
        }
1719
        if (notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled()) {
1720
            return;
1721
        }
1722
        newVersionOfUpdate();
1723
        commands.redo();
1724
        hasStrongChanges = true;
1725
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1726
    }
1727

    
1728
    @Override
1729
    synchronized public void undo() throws UndoException {
1730
        Command undo = commands.getNextUndoCommand();
1731
        try {
1732
            checkInEditingMode();
1733
        } catch (NeedEditingModeException ex) {
1734
            throw new UndoException(undo, ex);
1735
        }
1736
        if (notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled()) {
1737
            return;
1738
        }
1739
        newVersionOfUpdate();
1740
        commands.undo();
1741
        hasStrongChanges = true;
1742
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1743
    }
1744

    
1745
    @Override
1746
    public List getRedoInfos() {
1747
        if (isEditing() && (commands != null)) {
1748
            return commands.getRedoInfos();
1749
        } else {
1750
            return null;
1751
        }
1752
    }
1753

    
1754
    @Override
1755
    public List getUndoInfos() {
1756
        if (isEditing() && (commands != null)) {
1757
            return commands.getUndoInfos();
1758
        } else {
1759
            return null;
1760
        }
1761
    }
1762

    
1763
    public synchronized FeatureCommandsStack getCommandsStack()
1764
            throws DataException {
1765
        checkInEditingMode();
1766
        return commands;
1767
    }
1768

    
1769
    @Override
1770
    public boolean cancelEditingQuietly() {
1771
        try {
1772
            this.cancelEditing();
1773
            return true;
1774
        } catch (Exception ex) {
1775
            LOGGER.debug("Can't cancel editing", ex);
1776
            return false;
1777
        }
1778
    }
1779

    
1780
    @Override
1781
    synchronized public void cancelEditing() throws DataException {
1782
        if (spatialManager != null) {
1783
            spatialManager.cancelModifies();
1784
        }
1785
        try {
1786
            switch (mode) {
1787
                case MODE_QUERY:
1788
                    throw new NeedEditingModeException(this.getName());
1789

    
1790
                case MODE_APPEND:
1791
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1792
                        return;
1793
                    }
1794
                    provider.abortAppend();
1795
                    exitEditingMode();
1796
                    ((FeatureSelection) this.getSelection()).deselectAll();
1797
                    updateIndexes();
1798
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1799
                    break;
1800

    
1801
                case MODE_FULLEDIT:
1802
                    boolean clearSelection = this.hasStrongChanges;
1803
                    if (this.selection instanceof FeatureReferenceSelection) {
1804
                        clearSelection = this.hasInserts;
1805
                    }
1806
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1807
                        return;
1808
                    }
1809
                    exitEditingMode();
1810
                    if (clearSelection) {
1811
                        ((FeatureSelection) this.getSelection()).deselectAll();
1812
                    }
1813
                    updateIndexes();
1814
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1815
                    break;
1816

    
1817
                case MODE_PASS_THROUGH:
1818
                    if (notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled()) {
1819
                        return;
1820
                    }
1821
                    exitEditingMode();
1822
                    ((FeatureSelection) this.getSelection()).deselectAll();
1823
                    updateIndexes();
1824
                    notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1825
                    break;
1826
            }
1827
        } catch (Exception e) {
1828
            throw new StoreCancelEditingException(e, this.getName());
1829
        }
1830
    }
1831

    
1832
    @Override
1833
    public boolean finishEditingQuietly() {
1834
        try {
1835
            this.finishEditing();
1836
            return true;
1837
        } catch (Exception ex) {
1838
            LOGGER.debug("Can't finish editing", ex);
1839
            return false;
1840
        }
1841
    }
1842

    
1843
    @Override
1844
    synchronized public void finishEditing() throws DataException {
1845
        LOGGER.debug("finish editing of mode: {}", mode);
1846
        try {
1847

    
1848
            /*
1849
             * Selection needs to be cleared when editing stops
1850
             * to prevent conflicts with selection remaining from
1851
             * editing mode.
1852
             */
1853
//            ((FeatureSelection) this.getSelection()).deselectAll();
1854
            Map<String, List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1855
            switch (mode) {
1856
                case MODE_QUERY:
1857
                    throw new NeedEditingModeException(this.getName());
1858

    
1859
                case MODE_APPEND:
1860
                    if (selection != null) {
1861
                        selection = null;
1862
                    }
1863
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, this.editingSessionCode).isCanceled()) {
1864
                        return;
1865
                    }
1866
                    saveDALFile();
1867
                    provider.endAppend();
1868
                    exitEditingMode();
1869
                    this.updateComputedFields(computedFields);
1870
                    loadDALFile();
1871
                    updateIndexes();
1872
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING, this.editingSessionCode);
1873
                    break;
1874

    
1875
                case MODE_FULLEDIT:
1876
                    if (featureManager.hasChanges() || featureTypeManager.hasChanges()) {
1877
                        if (hasStrongChanges && !this.allowWrite()) {
1878
                            throw new WriteNotAllowedException(getName());
1879
                        }
1880
                        if (notifyChange(FeatureStoreNotification.PREPARING_FINISHEDITING,
1881
                                this.editingSessionCode).isCanceled()) {
1882
                            return;
1883
                        }
1884
                        if (hasStrongChanges) {
1885
                            validateFeaturesAtFinishEditing();
1886
                        }
1887
                        if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING,
1888
                                this.editingSessionCode,
1889
                                featureManager.getDeleted(),
1890
                                featureManager.getInsertedFeatures(),
1891
                                featureManager.getUpdatedFeatures(),
1892
                                featureTypeManager.getFeatureTypesChanged().iterator(),
1893
                                featureManager.isSelectionCompromised()).isCanceled()) {
1894
                            return;
1895
                        }
1896
                        saveDALFile();
1897
                        if (featureManager.isSelectionCompromised() && selection != null) {
1898
                            selection = null;
1899
                        }
1900
                        if (hasStrongChanges) {
1901
                            /*
1902
                         * This will throw a PerformEditingExceptionif the provider
1903
                         * does not accept the changes (for example, an invalid field name)
1904
                             */
1905
                            provider.performChanges(featureManager.getDeleted(),
1906
                                    featureManager.getInserted(),
1907
                                    featureManager.getUpdated(),
1908
                                    removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1909

    
1910
                        }
1911
                        this.updateComputedFields(computedFields);
1912
                        exitEditingMode();
1913
                        loadDALFile();
1914
                        updateIndexes();
1915
                        notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING, this.editingSessionCode);
1916
                    } else {
1917
                        exitEditingMode();
1918
                    }
1919
                    break;
1920
                case MODE_PASS_THROUGH:
1921
                    if (selection != null) {
1922
                        selection = null;
1923
                    }
1924
                    if (notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, this.editingSessionCode).isCanceled()) {
1925
                        return;
1926
                    }
1927
                    exitEditingMode();
1928
                    updateIndexes();
1929
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING, this.editingSessionCode);
1930
                    break;
1931
            }
1932
        } catch (ValidateFeaturesException | WriteNotAllowedException ex) {
1933
            // Don't notify failed.
1934
            throw ex;
1935
        } catch (PerformEditingException pee) {
1936
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING, this.editingSessionCode);
1937
            throw new WriteException(provider.getSourceId().toString(), pee);
1938
        } catch (Exception e) {
1939
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING, this.editingSessionCode);
1940
            throw new FinishEditingException(e);
1941
        }
1942
    }
1943

    
1944
    @Override
1945
    public String getEditingSession() {
1946
        return this.editingSessionCode;
1947
    }
1948

    
1949
    private Map<String, List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
1950
        Map<String, List<FeatureAttributeDescriptor>> r = new HashMap<>();
1951

    
1952
        List<FeatureType> theTypes = new ArrayList<>();
1953
        theTypes.addAll(this.getFeatureTypes());
1954
        theTypes.add(this.getDefaultFeatureType());
1955
        for (int n = 0; n < theTypes.size(); n++) {
1956
            FeatureType type = theTypes.get(n);
1957
            for (FeatureAttributeDescriptor attrdesc : type) {
1958
                FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
1959
                if (emulator != null) {
1960
                    List<FeatureAttributeDescriptor> l = r.get(type.getId());
1961
                    if (l == null) {
1962
                        l = new ArrayList<>();
1963
                        r.put(type.getId(), l);
1964
                    }
1965
                    l.add(attrdesc);
1966
                }
1967
            }
1968
        }
1969
        return r;
1970
    }
1971

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

    
1974
        List<FeatureType> theTypes = new ArrayList<>();
1975
        theTypes.addAll(this.getFeatureTypes());
1976
        theTypes.add(this.getDefaultFeatureType());
1977
        for (int n = 0; n < theTypes.size(); n++) {
1978
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1979
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1980
            if (x != null && !x.isEmpty()) {
1981
                for (FeatureAttributeDescriptor attrdesc : x) {
1982
                    if (type.get(attrdesc.getName()) == null) {
1983
                        type.add(attrdesc);
1984
                    }
1985
                }
1986
            }
1987
        }
1988

    
1989
    }
1990

    
1991
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
1992
        // FIXME: Falta por implementar
1993
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
1994
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
1995
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
1996
//                if (attributeDescriptor.isComputed()) {
1997
//                    target.remove(attributeDescriptor.getName());
1998
//                }
1999
//            }
2000
//        }
2001
        return ftypes;
2002
    }
2003

    
2004
    private void saveDALFile() {
2005
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2006
        try {
2007
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
2008
            if (resourcesStorage == null || resourcesStorage.isReadOnly()) {
2009
                return;
2010
            }
2011
            resource = resourcesStorage.getResource("dal");
2012
            if (resource == null || resource.isReadOnly()) {
2013
                return;
2014
            }
2015
            DALFile dalFile = DALFile.getDALFile();
2016
            dalFile.setStore(this);
2017
            if (!dalFile.isEmpty()) {
2018
                dalFile.write(resource);
2019
            }
2020
        } catch (Throwable ex) {
2021
            LOGGER.warn("Can't save DAL resource", ex);
2022
        } finally {
2023
            IOUtils.closeQuietly(resource);
2024
        }
2025
    }
2026

    
2027
    private void loadDALFile() {
2028
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
2029
        ResourcesStorage resourcesStorage = null;
2030
        try {
2031
            resourcesStorage = this.getResourcesStorage();
2032
            if (resourcesStorage == null) {
2033
                return;
2034
            }
2035
            resource = resourcesStorage.getResource("dal");
2036
            if (resource == null || !resource.exists()) {
2037
                return;
2038
            }
2039
            DALFile dalFile = DALFile.getDALFile(resource);
2040
            if (!dalFile.isEmpty()) {
2041
                dalFile.updateStore(this);
2042
            }
2043
        } catch (Throwable ex) {
2044
            if (resource == null || resourcesStorage == null) {
2045
                if (resourcesStorage == null) {
2046
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=null)", ex);
2047
                } else {
2048
                    LOGGER.warn("Can't load DAL resource (resname=null, resurl=null, storage=" + resourcesStorage.getClass().getName() + ").", ex);
2049
                }
2050
            } else {
2051
                LOGGER.warn("Can't load DAL resource (resname=" + resource.getName() + ", resurl=" + Objects.toString(resource.getURL()) + ", storage=" + resourcesStorage.getClass().getName() + ").", ex);
2052
            }
2053
        } finally {
2054
            IOUtils.closeQuietly(resource);
2055
        }
2056
    }
2057

    
2058
    /**
2059
     * Save changes in the provider without leaving the edit mode. Do not call
2060
     * observers to communicate a change of ediding mode. The operation's
2061
     * history is eliminated to prevent inconsistencies in the data.
2062
     *
2063
     * @throws DataException
2064
     */
2065
    @Override
2066
    synchronized public void commitChanges() throws DataException {
2067
        LOGGER.debug("commitChanges of mode: {}", mode);
2068
        if (!canCommitChanges()) {
2069
            throw new WriteNotAllowedException(getName());
2070
        }
2071
        try {
2072
            switch (mode) {
2073
                case MODE_QUERY:
2074
                    throw new NeedEditingModeException(this.getName());
2075

    
2076
                case MODE_APPEND:
2077
                    this.provider.endAppend();
2078
                    exitEditingMode();
2079
                    invalidateIndexes();
2080
                    this.provider.beginAppend();
2081
                    hasInserts = false;
2082
                    break;
2083

    
2084
                case MODE_FULLEDIT:
2085
                    if (hasStrongChanges && !this.allowWrite()) {
2086
                        throw new WriteNotAllowedException(getName());
2087
                    }
2088
                    // FIXME: OOhh!!!! no se disparan eventos, VCSGis no se entera de estos cambios.
2089
                    if (hasStrongChanges) {
2090
                        validateFeaturesAtFinishEditing();
2091
                        provider.performChanges(featureManager.getDeleted(),
2092
                                featureManager.getInserted(),
2093
                                featureManager.getUpdated(),
2094
                                removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2095
                    }
2096
                    invalidateIndexes();
2097
                    featureManager = new FeatureManager(this);
2098
                    featureTypeManager = new FeatureTypeManager(this);
2099
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
2100

    
2101
                    commands
2102
                            = new DefaultFeatureCommandsStack(this, featureManager,
2103
                                    spatialManager, featureTypeManager);
2104
                    featureCount = null;
2105
                    hasStrongChanges = false;
2106
                    hasInserts = false;
2107
                    break;
2108
            }
2109
        } catch (Exception e) {
2110
            throw new FinishEditingException(e);
2111
        }
2112
    }
2113

    
2114
    @Override
2115
    synchronized public boolean canCommitChanges() throws DataException {
2116
        if (!this.allowWrite()) {
2117
            return false;
2118
        }
2119
        switch (mode) {
2120
            default:
2121
            case MODE_QUERY:
2122
                return false;
2123

    
2124
            case MODE_APPEND:
2125
                return true;
2126

    
2127
            case MODE_FULLEDIT:
2128
                List types = this.getFeatureTypes();
2129
                for (int i = 0; i < types.size(); i++) {
2130
                    Object type = types.get(i);
2131
                    if (type instanceof DefaultEditableFeatureType) {
2132
                        if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
2133
                            return false;
2134
                        }
2135
                    }
2136
                }
2137
                return true;
2138
        }
2139
    }
2140

    
2141
    @Override
2142
    public void beginEditingGroup(String description)
2143
            throws NeedEditingModeException {
2144
        checkInEditingMode();
2145
        commands.startComplex(description);
2146
    }
2147

    
2148
    @Override
2149
    public void endEditingGroup() throws NeedEditingModeException {
2150
        checkInEditingMode();
2151
        commands.endComplex();
2152
    }
2153

    
2154
    @Override
2155
    public boolean isAppendModeSupported() {
2156
        return this.provider.supportsAppendMode();
2157
    }
2158

    
2159
    @Override
2160
    public void export(DataServerExplorer explorer, String provider,
2161
            NewFeatureStoreParameters params, String name) throws DataException {
2162

    
2163
        if (this.getFeatureTypes().size() != 1) {
2164
            throw new NotYetImplemented(
2165
                    "export whith more than one type not yet implemented");
2166
        }
2167
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2168
        FeatureStore target = null;
2169
        FeatureSet features = null;
2170
        DisposableIterator iterator = null;
2171
        try {
2172
            FeatureType type = this.getDefaultFeatureType();
2173
            if ((params.getDefaultFeatureType() == null)
2174
                    || (params.getDefaultFeatureType().size() == 0)) {
2175
                params.setDefaultFeatureType(type.getEditable());
2176

    
2177
            }
2178
            explorer.add(provider, params, true);
2179
            DataManager manager = DALLocator.getDataManager();
2180

    
2181
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2182
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2183

    
2184
            target = (FeatureStore) manager.openStore(provider, openParams);
2185
            FeatureType targetType = target.getDefaultFeatureType();
2186

    
2187
            target.edit(MODE_APPEND);
2188
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2189
            if (featureSelection.getSize() > 0) {
2190
                features = this.getFeatureSelection();
2191
            } else {
2192
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2193
                    FeatureQuery query = createFeatureQuery();
2194
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2195
                        query.getOrder().add(pkattr.getName(), true);
2196
                    }
2197
                    features = this.getFeatureSet(query);
2198
                } else {
2199
                    features = this.getFeatureSet();
2200
                }
2201
            }
2202
            iterator = features.fastIterator();
2203
            while (iterator.hasNext()) {
2204
                DefaultFeature feature = (DefaultFeature) iterator.next();
2205
                target.insert(target.createNewFeature(targetType, feature));
2206
            }
2207
            target.finishEditing();
2208
            target.dispose();
2209
        } catch (Exception e) {
2210
            throw new DataExportException(e, params.toString());
2211
        } finally {
2212
            dispose(iterator);
2213
            dispose(features);
2214
            dispose(target);
2215
        }
2216
    }
2217

    
2218
    @Override
2219
    public void copyTo(final FeatureStore target) {
2220
        boolean finishEditingAtEnd = false;
2221
        try {
2222
            if (!target.isEditing() && !target.isAppending()) {
2223
                finishEditingAtEnd = true;
2224
                target.edit(MODE_APPEND);
2225
            }
2226
            this.accept((Object obj) -> {
2227
                Feature f_src = (Feature) obj;
2228
                EditableFeature f_dst = target.createNewFeature(f_src);
2229
                target.insert(f_dst);
2230
            });
2231
            if (finishEditingAtEnd) {
2232
                target.finishEditing();
2233
            }
2234

    
2235
        } catch (Exception ex) {
2236
            try {
2237
                if (finishEditingAtEnd) {
2238
                    target.cancelEditing();
2239
                }
2240
            } catch (Exception ex1) {
2241
            }
2242
            throw new RuntimeException("Can't copy store.", ex);
2243
        }
2244

    
2245
    }
2246

    
2247
    //
2248
    // ====================================================================
2249
    // Obtencion de datos
2250
    // getDataCollection, getFeatureCollection
2251
    //
2252
    @Override
2253
    public DataSet getDataSet() throws DataException {
2254
        checkNotInAppendMode();
2255
        FeatureQuery query
2256
                = new DefaultFeatureQuery(this.getDefaultFeatureType());
2257
        return new DefaultFeatureSet(this, query);
2258
    }
2259

    
2260
    @Override
2261
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2262
        checkNotInAppendMode();
2263
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2264
    }
2265

    
2266
    @Override
2267
    public void getDataSet(Observer observer) throws DataException {
2268
        checkNotInAppendMode();
2269
        this.getFeatureSet(null, observer);
2270
    }
2271

    
2272
    @Override
2273
    public void getDataSet(DataQuery dataQuery, Observer observer)
2274
            throws DataException {
2275
        checkNotInAppendMode();
2276
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2277
    }
2278

    
2279
    @Override
2280
    public FeatureSet getFeatureSet() throws DataException {
2281
        return this.getFeatureSet((FeatureQuery) null);
2282
    }
2283

    
2284
    @Override
2285
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2286
            throws DataException {
2287
        checkNotInAppendMode();
2288
        if (featureQuery == null) {
2289
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2290
        }
2291
        return new DefaultFeatureSet(this, featureQuery);
2292
    }
2293

    
2294
    @Override
2295
    public FeatureSet getFeatureSet(String filter) throws DataException {
2296
        return this.getFeatureSet(filter, null, true);
2297
    }
2298

    
2299
    @Override
2300
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2301
        return this.getFeatureSet(filter, sortBy, true);
2302
    }
2303

    
2304
    @Override
2305
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2306
        return this.getFeatureSet(filter, null, true);
2307
    }
2308

    
2309
    @Override
2310
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2311
        return this.getFeatureSet(filter, sortBy, true);
2312
    }
2313

    
2314
    @Override
2315
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2316
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2317
        return this.getFeatureSet(query);
2318
    }
2319

    
2320
    @Override
2321
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2322
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2323
        return this.getFeatureSet(query);
2324
    }
2325

    
2326
    @Override
2327
    public List<Feature> getFeatures(String filter) {
2328
        return this.getFeatures(filter, null, true);
2329
    }
2330

    
2331
    @Override
2332
    public List<Feature> getFeatures(String filter, String sortBy) {
2333
        return this.getFeatures(filter, sortBy, true);
2334
    }
2335

    
2336
    @Override
2337
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc) {
2338
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2339
        return this.getFeatures(query, 0);
2340
    }
2341

    
2342
    @Override
2343
    public List<Feature> getFeatures(Expression filter) {
2344
        return this.getFeatures(filter, null, true);
2345
    }
2346

    
2347
    @Override
2348
    public List<Feature> getFeatures(Expression filter, String sortBy) {
2349
        return this.getFeatures(filter, sortBy, true);
2350
    }
2351

    
2352
    @Override
2353
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc) {
2354
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2355
        return this.getFeatures(query, 0);
2356
    }
2357

    
2358
    @Override
2359
    public List<Feature> getFeatures(FeatureQuery query) {
2360
        return this.getFeatures(query, 0);
2361
    }
2362

    
2363
    @Override
2364
    public List<Feature> getFeatures(FeatureQuery query, int pageSize) {
2365
        try {
2366
            if (pageSize <= 0) {
2367
                pageSize = 100;
2368
            }
2369
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2370
            return pager.asList();
2371
        } catch (BaseException ex) {
2372
            throw new RuntimeException("Can't create the list of features.", ex);
2373
        }
2374
    }
2375

    
2376
    @Override
2377
    public List<Feature> getFeatures() {
2378
        return this.getFeatures(null, 0);
2379
    }
2380

    
2381
    @Override
2382
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2383
        return this.getFeatures64(null, 0);
2384
    }
2385

    
2386
    @Override
2387
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2388
        return this.getFeatures64(filter, null, true);
2389
    }
2390

    
2391
    @Override
2392
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc) {
2393
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2394
        return this.getFeatures64(query, 0);
2395
    }
2396

    
2397
    @Override
2398
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize) {
2399
        try {
2400
            if (pageSize <= 0) {
2401
                pageSize = 100;
2402
            }
2403
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2404
            return pager;
2405
        } catch (BaseException ex) {
2406
            throw new RuntimeException("Can't create the list of features.", ex);
2407
        }
2408
    }
2409

    
2410
    @Override
2411
    public Feature first() throws DataException {
2412
        return this.findFirst((FeatureQuery) null);
2413
    }
2414

    
2415
    @Override
2416
    public Feature findFirst(String filter) throws DataException {
2417
        return this.findFirst(filter, (String) null, true);
2418
    }
2419

    
2420
    @Override
2421
    public Feature findFirst(String filter, String sortBy) throws DataException {
2422
        return this.findFirst(filter, sortBy, true);
2423
    }
2424

    
2425
    @Override
2426
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2427
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2428
        return findFirst(query);
2429
    }
2430

    
2431
    @Override
2432
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2433
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2434
        return findFirst(query);
2435
    }
2436

    
2437
    @Override
2438
    public Feature findFirst(Expression filter) throws DataException {
2439
        return this.findFirst(filter, (String) null, true);
2440
    }
2441

    
2442
    @Override
2443
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2444
        return this.findFirst(filter, sortBy, true);
2445
    }
2446

    
2447
    @Override
2448
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2449
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2450
        return findFirst(query);
2451
    }
2452

    
2453
    @Override
2454
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2455
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2456
        return findFirst(query);
2457
    }
2458

    
2459
    @Override
2460
    public Feature findFirst(FeatureQuery query) throws DataException {
2461
        if (query == null) {
2462
            query = this.createFeatureQuery();
2463
        } else {
2464
            query = query.getCopy();
2465
        }
2466
        query.setLimit(1);
2467
        final MutableObject<Feature> feature = new MutableObject<>();
2468
        try {
2469
            this.accept((Object obj) -> {
2470
                feature.setValue((Feature) obj);
2471
                throw new VisitCanceledException();
2472
            }, query);
2473
        } catch (VisitCanceledException ex) {
2474

    
2475
        } catch (DataException ex) {
2476
            throw ex;
2477
        } catch (Exception ex) {
2478
            throw new RuntimeException("", ex);
2479
        }
2480
        return feature.getValue();
2481
    }
2482

    
2483
    @Override
2484
    public void accept(Visitor visitor) throws BaseException {
2485
        this.accept(visitor, null);
2486
    }
2487

    
2488
    @Override
2489
    public void accept(Visitor visitor, DataQuery dataQuery)
2490
            throws BaseException {
2491
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2492
        try {
2493
            set.accept(visitor);
2494
        } finally {
2495
            set.dispose();
2496
        }
2497
    }
2498

    
2499
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2500
            throws DataException {
2501
        DefaultFeatureType fType
2502
                = (DefaultFeatureType) this.getFeatureType(featureQuery
2503
                        .getFeatureTypeId());
2504
        if (featureQuery.hasAttributeNames()
2505
                || featureQuery.hasConstantsAttributeNames()
2506
                || fType.hasRequiredFields()) {
2507
            if (featureQuery.hasGroupByColumns()) {
2508
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false);
2509
            } else {
2510
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2511
            }
2512
        }
2513
        return fType;
2514
    }
2515

    
2516
    @Override
2517
    public void getFeatureSet(Observer observer) throws DataException {
2518
        checkNotInAppendMode();
2519
        this.getFeatureSet(null, observer);
2520
    }
2521

    
2522
    @Override
2523
    public void getFeatureSet(FeatureQuery query, Observer observer)
2524
            throws DataException {
2525
        class LoadInBackGround implements Runnable {
2526

    
2527
            private final FeatureStore store;
2528
            private final FeatureQuery query;
2529
            private final Observer observer;
2530

    
2531
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2532
                    Observer observer) {
2533
                this.store = store;
2534
                this.query = query;
2535
                this.observer = observer;
2536
            }
2537

    
2538
            void notify(FeatureStoreNotification theNotification) {
2539
                observer.update(store, theNotification);
2540
            }
2541

    
2542
            @Override
2543
            public void run() {
2544
                FeatureSet set = null;
2545
                try {
2546
                    set = store.getFeatureSet(query);
2547
                    notify(new DefaultFeatureStoreNotification(store,
2548
                            FeatureStoreNotification.LOAD_FINISHED, set));
2549
                } catch (Exception e) {
2550
                    notify(new DefaultFeatureStoreNotification(store,
2551
                            FeatureStoreNotification.LOAD_FINISHED, e));
2552
                } finally {
2553
                    dispose(set);
2554
                }
2555
            }
2556
        }
2557

    
2558
        checkNotInAppendMode();
2559
        if (query == null) {
2560
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2561
        }
2562
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2563
        Thread thread = new Thread(task, "Load Feature Set in background");
2564
        thread.start();
2565
    }
2566

    
2567
    @Override
2568
    public Feature getFeatureByReference(FeatureReference reference)
2569
            throws DataException {
2570
        checkNotInAppendMode();
2571
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2572
        FeatureType featureType;
2573
        if (ref.getFeatureTypeId() == null) {
2574
            featureType = this.getDefaultFeatureType();
2575
        } else {
2576
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2577
        }
2578
        return this.getFeatureByReference(reference, featureType);
2579
    }
2580

    
2581
    @Override
2582
    public Feature getFeatureByReference(FeatureReference reference,
2583
            FeatureType featureType) throws DataException {
2584
        checkNotInAppendMode();
2585
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2586
        if (this.mode == MODE_FULLEDIT) {
2587
            Feature f = featureManager.get(reference, this, featureType);
2588
            if (f != null) {
2589
                return f;
2590
            }
2591
        }
2592

    
2593
        FeatureType sourceFeatureType = featureType;
2594
        if (!this.transforms.isEmpty()) {
2595
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2596
        }
2597
        // TODO comprobar que el id es de este store
2598

    
2599
        DefaultFeature feature
2600
                = new DefaultFeature(this,
2601
                        this.provider.getFeatureProviderByReference(
2602
                                (FeatureReferenceProviderServices) reference, sourceFeatureType));
2603

    
2604
        if (!this.transforms.isEmpty()) {
2605
            return this.transforms.applyTransform(feature, featureType);
2606
        }
2607
        return feature;
2608
    }
2609

    
2610
    //
2611
    // ====================================================================
2612
    // Gestion de features
2613
    //
2614
    private FeatureType fixFeatureType(DefaultFeatureType type)
2615
            throws DataException {
2616
        FeatureType original = this.getDefaultFeatureType();
2617

    
2618
        if ((type == null) || type.equals(original)) {
2619
            return original;
2620
        } else {
2621
            if (!type.isSubtypeOf(original)) {
2622
                Iterator iter = this.getFeatureTypes().iterator();
2623
                FeatureType tmpType;
2624
                boolean found = false;
2625
                while (iter.hasNext()) {
2626
                    tmpType = (FeatureType) iter.next();
2627
                    if (type.equals(tmpType)) {
2628
                        return type;
2629

    
2630
                    } else if (type.isSubtypeOf(tmpType)) {
2631
                        found = true;
2632
                        original = tmpType;
2633
                        break;
2634
                    }
2635

    
2636
                }
2637
                if (!found) {
2638
                    throw new IllegalFeatureTypeException(getName());
2639
                }
2640
            }
2641
        }
2642

    
2643
        // Checks that type has all fields of pk
2644
        // else add the missing attributes at the end.
2645
        if (!original.hasOID()) {
2646
            // Gets original pk attributes
2647
            DefaultEditableFeatureType edOriginal
2648
                    = (DefaultEditableFeatureType) original.getEditable();
2649
            FeatureAttributeDescriptor orgAttr;
2650
            Iterator edOriginalIter = edOriginal.iterator();
2651
            while (edOriginalIter.hasNext()) {
2652
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2653
                if (!orgAttr.isPrimaryKey()) {
2654
                    edOriginalIter.remove();
2655
                }
2656
            }
2657

    
2658
            // Checks if all pk attributes are in type
2659
            Iterator typeIterator;
2660
            edOriginalIter = edOriginal.iterator();
2661
            FeatureAttributeDescriptor attr;
2662
            while (edOriginalIter.hasNext()) {
2663
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2664
                typeIterator = type.iterator();
2665
                while (typeIterator.hasNext()) {
2666
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2667
                    if (attr.getName().equals(orgAttr.getName())) {
2668
                        edOriginalIter.remove();
2669
                        break;
2670
                    }
2671
                }
2672
            }
2673

    
2674
            // add missing pk attributes if any
2675
            if (edOriginal.size() > 0) {
2676
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2677
                DefaultEditableFeatureType edType
2678
                        = (DefaultEditableFeatureType) original.getEditable();
2679
                edType.clear();
2680
                edType.addAll(type);
2681
                edType.addAll(edOriginal);
2682
                if (!isEditable) {
2683
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2684
                }
2685
            }
2686

    
2687
        }
2688

    
2689
        return type;
2690
    }
2691

    
2692
    private void validateFeaturesAtFinishEditing() throws ValidateFeaturesException {
2693
        try {
2694
            checkInEditingMode();
2695
            FeatureType type = this.getDefaultFeatureTypeQuietly();
2696
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
2697

    
2698
            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS : 0;
2699
            checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
2700
            if (checks == 0) {
2701
                return;
2702
            }
2703

    
2704
            Iterator<EditableFeature> features = new ChainedIterator<>(
2705
                    featureManager.getInsertedFeatures(),
2706
                    featureManager.getUpdatedFeatures()
2707
            );
2708
            while (features.hasNext()) {
2709
                EditableFeature feature = features.next();
2710
                rules.validate(feature, checks);
2711
            }
2712
        } catch (Exception ex) {
2713
            throw new ValidateFeaturesException(this.getName(), ex);
2714
        }
2715
    }
2716

    
2717
    @Override
2718
    public FeatureType getDefaultFeatureType() throws DataException {
2719
        try {
2720

    
2721
            if (isEditing()) {
2722
                FeatureType auxFeatureType
2723
                        = featureTypeManager.getType(defaultFeatureType.getId());
2724
                if (auxFeatureType != null) {
2725
                    return avoidEditable(auxFeatureType);
2726
                }
2727
            }
2728
            FeatureType type = this.transforms.getDefaultFeatureType();
2729
            if (type != null) {
2730
                return avoidEditable(type);
2731
            }
2732

    
2733
            return avoidEditable(defaultFeatureType);
2734

    
2735
        } catch (Exception e) {
2736
            throw new GetFeatureTypeException(e, getName());
2737
        }
2738
    }
2739

    
2740
    @Override
2741
    public FeatureType getDefaultFeatureTypeQuietly() {
2742
        try {
2743
            return this.getDefaultFeatureType();
2744
        } catch (Exception ex) {
2745
            return null;
2746
        }
2747
    }
2748

    
2749
    private FeatureType avoidEditable(FeatureType ft) {
2750
        if (ft instanceof EditableFeatureType) {
2751
            return ((EditableFeatureType) ft).getNotEditableCopy();
2752
        } else {
2753
            return ft;
2754
        }
2755
    }
2756

    
2757
    @Override
2758
    public FeatureType getFeatureType(String featureTypeId)
2759
            throws DataException {
2760
        if (featureTypeId == null) {
2761
            return this.getDefaultFeatureType();
2762
        }
2763
        try {
2764
            if (isEditing()) {
2765
                FeatureType auxFeatureType
2766
                        = featureTypeManager.getType(featureTypeId);
2767
                if (auxFeatureType != null) {
2768
                    return auxFeatureType;
2769
                }
2770
            }
2771
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2772
            if (type != null) {
2773
                return type;
2774
            }
2775
            Iterator iter = this.featureTypes.iterator();
2776
            while (iter.hasNext()) {
2777
                type = (FeatureType) iter.next();
2778
                if (type.getId().equals(featureTypeId)) {
2779
                    return type;
2780
                }
2781
            }
2782
            return null;
2783
        } catch (Exception e) {
2784
            throw new GetFeatureTypeException(e, getName());
2785
        }
2786
    }
2787

    
2788
    public FeatureType getProviderDefaultFeatureType() {
2789
        return defaultFeatureType;
2790
    }
2791

    
2792
    @Override
2793
    public List getFeatureTypes() throws DataException {
2794
        try {
2795
            List types;
2796
            if (isEditing()) {
2797
                types = new ArrayList();
2798
                for (FeatureType type : featureTypes) {
2799
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2800
                    if (typeaux != null) {
2801
                        types.add(typeaux);
2802
                    } else {
2803
                        types.add(type);
2804
                    }
2805
                }
2806
                Iterator it = featureTypeManager.newsIterator();
2807
                while (it.hasNext()) {
2808
                    FeatureType type = (FeatureType) it.next();
2809
                    types.add(type);
2810
                }
2811
            } else {
2812
                types = this.transforms.getFeatureTypes();
2813
                if (types == null) {
2814
                    types = featureTypes;
2815
                }
2816
            }
2817
            return Collections.unmodifiableList(types);
2818
        } catch (Exception e) {
2819
            throw new GetFeatureTypeException(e, getName());
2820
        }
2821
    }
2822

    
2823
    public List getProviderFeatureTypes() throws DataException {
2824
        return Collections.unmodifiableList(this.featureTypes);
2825
    }
2826

    
2827
    @Override
2828
    public Feature createFeature(FeatureProvider data) throws DataException {
2829
        DefaultFeature feature = new DefaultFeature(this, data);
2830
        return feature;
2831
    }
2832

    
2833
    public Feature createFeature(FeatureProvider data, FeatureType type)
2834
            throws DataException {
2835
        // FIXME: falta por implementar
2836
        // Comprobar si es un subtipo del feature de data
2837
        // y construir un feature usando el subtipo.
2838
        // Probablemente requiera generar una copia del data.
2839
        throw new NotYetImplemented();
2840
    }
2841

    
2842
    @Override
2843
    public EditableFeature createNewFeature(FeatureType type,
2844
            Feature defaultValues) throws DataException {
2845
        try {
2846
            FeatureProvider data = createNewFeatureProvider(type);
2847
            DefaultEditableFeature feature
2848
                    = new DefaultEditableFeature(this, data);
2849
            feature.initializeValues(defaultValues);
2850
            data.setNew(true);
2851

    
2852
            return feature;
2853
        } catch (Exception e) {
2854
            throw new CreateFeatureException(e, getName());
2855
        }
2856
    }
2857

    
2858
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2859
            throws DataException {
2860
        type = this.fixFeatureType((DefaultFeatureType) type);
2861
        FeatureProvider data = this.provider.createFeatureProvider(type);
2862
        data.setNew(true);
2863
        if (type.hasOID() && (data.getOID() == null)) {
2864
            data.setOID(this.provider.createNewOID());
2865
        } else {
2866
            data.setOID(this.getTemporalOID());
2867
        }
2868
        return data;
2869

    
2870
    }
2871

    
2872
    @Override
2873
    public EditableFeature createNewFeature(FeatureType type,
2874
            boolean defaultValues) throws DataException {
2875
        try {
2876
            FeatureProvider data = createNewFeatureProvider(type);
2877
            DefaultEditableFeature feature
2878
                    = new DefaultEditableFeature(this, data);
2879
            if (defaultValues) {
2880
                feature.initializeValues();
2881
            }
2882
            return feature;
2883
        } catch (Exception e) {
2884
            throw new CreateFeatureException(e, getName());
2885
        }
2886
    }
2887

    
2888
    @Override
2889
    public EditableFeature createNewFeature(boolean defaultValues)
2890
            throws DataException {
2891
        return this.createNewFeature(this.getDefaultFeatureType(),
2892
                defaultValues);
2893
    }
2894

    
2895
    @Override
2896
    public EditableFeature createNewFeature() throws DataException {
2897
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2898
    }
2899

    
2900
    @Override
2901
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2902
        FeatureType ft = this.getDefaultFeatureType();
2903
        EditableFeature f = this.createNewFeature(ft, false);
2904
        f.copyFrom(defaultValues);
2905
        return f;
2906
    }
2907

    
2908
    @Override
2909
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2910
        FeatureType ft = this.getDefaultFeatureType();
2911
        EditableFeature f = this.createNewFeature(ft, false);
2912
        f.copyFrom(defaultValues);
2913
        return f;
2914
    }
2915

    
2916
    @Override
2917
    public EditableFeatureType createFeatureType() {
2918
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2919
        return ftype;
2920
    }
2921

    
2922
    @Override
2923
    public EditableFeatureType createFeatureType(String id) {
2924
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2925
        return ftype;
2926
    }
2927

    
2928
    //
2929
    // ====================================================================
2930
    // Index related methods
2931
    //
2932
    @Override
2933
    public FeatureIndexes getIndexes() {
2934
        return this.indexes;
2935
    }
2936

    
2937
    @Override
2938
    public FeatureIndex createIndex(FeatureType featureType,
2939
            String attributeName, String indexName) throws DataException {
2940
        return createIndex(null, featureType, attributeName, indexName);
2941
    }
2942

    
2943
    @Override
2944
    public FeatureIndex createIndex(String indexTypeName,
2945
            FeatureType featureType, String attributeName, String indexName)
2946
            throws DataException {
2947

    
2948
        return createIndex(indexTypeName, featureType, attributeName,
2949
                indexName, false, null);
2950
    }
2951

    
2952
    @Override
2953
    public FeatureIndex createIndex(FeatureType featureType,
2954
            String attributeName, String indexName, Observer observer)
2955
            throws DataException {
2956
        return createIndex(null, featureType, attributeName, indexName,
2957
                observer);
2958
    }
2959

    
2960
    @Override
2961
    public FeatureIndex createIndex(String indexTypeName,
2962
            FeatureType featureType, String attributeName, String indexName,
2963
            final Observer observer) throws DataException {
2964

    
2965
        return createIndex(indexTypeName, featureType, attributeName,
2966
                indexName, true, observer);
2967
    }
2968

    
2969
    private FeatureIndex createIndex(String indexTypeName,
2970
            FeatureType featureType, String attributeName, String indexName,
2971
            boolean background, final Observer observer) throws DataException {
2972

    
2973
        checkNotInAppendMode();
2974
        FeatureIndexProviderServices index;
2975
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2976
                featureType, indexName,
2977
                featureType.getAttributeDescriptor(attributeName));
2978

    
2979
        try {
2980
            index.fill(background, observer);
2981
        } catch (FeatureIndexException e) {
2982
            throw new InitializeException(index.getName(), e);
2983
        }
2984

    
2985
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2986
        return index;
2987
    }
2988

    
2989
    //
2990
    // ====================================================================
2991
    // Transforms related methods
2992
    //
2993
    @Override
2994
    public FeatureStoreTransforms getTransforms() {
2995
        return this.transforms;
2996
    }
2997

    
2998
    @Override
2999
    public FeatureQuery createFeatureQuery() {
3000
        return new DefaultFeatureQuery();
3001
    }
3002

    
3003
    @Override
3004
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
3005
        FeatureQuery query = null;
3006
        if (filter != null) {
3007
            query = this.createFeatureQuery();
3008
            query.setFilter(filter);
3009
        }
3010
        if (!StringUtils.isBlank(sortBy)) {
3011
            if (query == null) {
3012
                query = this.createFeatureQuery();
3013
            }
3014
            if (StringUtils.containsAny(sortBy, "(", ")")) {
3015
                throw new IllegalArgumentException("Incorrect sortBy expression");
3016
            }
3017
            String[] attrnames;
3018
            if (sortBy.contains(",")) {
3019
                attrnames = StringUtils.split(sortBy, ",");
3020
            } else {
3021
                attrnames = new String[]{sortBy};
3022
            }
3023
            for (String attrname : attrnames) {
3024
                attrname = attrname.trim();
3025
                if (attrname.startsWith("-")) {
3026
                    query.getOrder().add(attrname.substring(1).trim(), false);
3027
                } else if (attrname.endsWith("-")) {
3028
                    query.getOrder().add(attrname.substring(0, sortBy.length() - 1).trim(), false);
3029
                } else if (attrname.startsWith("+")) {
3030
                    query.getOrder().add(attrname.substring(1).trim(), true);
3031
                } else if (attrname.endsWith("-")) {
3032
                    query.getOrder().add(attrname.substring(0, sortBy.length() - 1).trim(), true);
3033
                } else {
3034
                    query.getOrder().add(attrname, asc);
3035
                }
3036
            }
3037
        }
3038
        if (query != null) {
3039
            query.retrievesAllAttributes();
3040
        }
3041
        return query;
3042
    }
3043

    
3044
    @Override
3045
    public FeatureQuery createFeatureQuery(String filter) {
3046
        return this.createFeatureQuery(
3047
                ExpressionUtils.createExpression(filter),
3048
                (String) null,
3049
                true
3050
        );
3051
    }
3052

    
3053
    @Override
3054
    public FeatureQuery createFeatureQuery(Expression filter) {
3055
        return this.createFeatureQuery(
3056
                filter,
3057
                (String) null,
3058
                true
3059
        );
3060
    }
3061

    
3062
    @Override
3063
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
3064
        if (StringUtils.isBlank(filter)) {
3065
            return this.createFeatureQuery(
3066
                    (Expression) null,
3067
                    sortBy,
3068
                    asc
3069
            );
3070
        } else {
3071
            return this.createFeatureQuery(
3072
                    ExpressionUtils.createExpression(filter),
3073
                    sortBy,
3074
                    asc
3075
            );
3076
        }
3077
    }
3078

    
3079
    @Override
3080
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
3081
        FeatureQuery query = null;
3082
        if (filter != null) {
3083
            query = this.createFeatureQuery();
3084
            query.setFilter(filter);
3085
        }
3086
        if (sortBy != null) {
3087
            if (query == null) {
3088
                query = this.createFeatureQuery();
3089
            }
3090
            query.getOrder().add(sortBy, asc);
3091
        }
3092

    
3093
        if (query != null) {
3094
            query.retrievesAllAttributes();
3095
        }
3096
        return query;
3097
    }
3098

    
3099
    @Override
3100
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3101
        if (StringUtils.isBlank(filter)) {
3102
            return this.createFeatureQuery(
3103
                    (Expression) null,
3104
                    sortBy,
3105
                    asc
3106
            );
3107
        } else {
3108
            return this.createFeatureQuery(
3109
                    ExpressionUtils.createExpression(filter),
3110
                    sortBy,
3111
                    asc
3112
            );
3113
        }
3114
    }
3115

    
3116
    @Override
3117
    public DataQuery createQuery() {
3118
        return createFeatureQuery();
3119
    }
3120

    
3121
    //
3122
    // ====================================================================
3123
    // UndoRedo related methods
3124
    //
3125
    @Override
3126
    public boolean canRedo() {
3127
        return commands.canRedo();
3128
    }
3129

    
3130
    @Override
3131
    public boolean canUndo() {
3132
        return commands.canUndo();
3133
    }
3134

    
3135
    @Override
3136
    public void redo(int num) throws RedoException {
3137
        for (int i = 0; i < num; i++) {
3138
            redo();
3139
        }
3140
    }
3141

    
3142
    @Override
3143
    public void undo(int num) throws UndoException {
3144
        for (int i = 0; i < num; i++) {
3145
            undo();
3146
        }
3147
    }
3148

    
3149
    //
3150
    // ====================================================================
3151
    // Metadata related methods
3152
    //
3153
    @Override
3154
    public Object getMetadataID() {
3155
        return this.provider.getSourceId();
3156
    }
3157

    
3158
    @Override
3159
    public void delegate(DynObject dynObject) {
3160
        this.metadata.delegate(dynObject);
3161
    }
3162

    
3163
    @Override
3164
    public DynClass getDynClass() {
3165
        return this.metadata.getDynClass();
3166
    }
3167

    
3168
    @Override
3169
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3170
        try {
3171
            if (this.transforms.hasDynValue(name)) {
3172
                return this.transforms.getDynValue(name);
3173
            }
3174
            if (this.metadata.hasDynValue(name)) {
3175
                return this.metadata.getDynValue(name);
3176
            }
3177
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3178
                return this.provider.getProviderName();
3179
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3180
                return this.provider.getSourceId();
3181
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3182
                try {
3183
                    return this.getDefaultFeatureType();
3184
                } catch (DataException e) {
3185
                    return null;
3186
                }
3187
            }
3188
            return this.metadata.getDynValue(name);
3189
        } catch (Exception ex) {
3190
            LOGGER.debug("Can't retrieve the value of '" + name + "' in store '" + this.getName() + "'.", ex);
3191
            return null;
3192
        }
3193
    }
3194

    
3195
    @Override
3196
    public boolean hasDynValue(String name) {
3197
        if (this.transforms.hasDynValue(name)) {
3198
            return true;
3199
        }
3200
        return this.metadata.hasDynValue(name);
3201
    }
3202

    
3203
    @Override
3204
    public boolean hasDynMethod(String name) {
3205
        return ((DynObject_v2) this.metadata).hasDynMethod(name);
3206
    }
3207

    
3208
    @Override
3209
    public void implement(DynClass dynClass) {
3210
        this.metadata.implement(dynClass);
3211
    }
3212

    
3213
    @Override
3214
    public Object invokeDynMethod(String name, Object[] args)
3215
            throws DynMethodException {
3216
        return this.metadata.invokeDynMethod(this, name, args);
3217
    }
3218

    
3219
    @Override
3220
    public Object invokeDynMethod(int code, Object[] args)
3221
            throws DynMethodException {
3222
        return this.metadata.invokeDynMethod(this, code, args);
3223
    }
3224

    
3225
    @Override
3226
    public void setDynValue(String name, Object value)
3227
            throws DynFieldNotFoundException {
3228
        if (this.transforms.hasDynValue(name)) {
3229
            this.transforms.setDynValue(name, value);
3230
            return;
3231
        }
3232
        this.metadata.setDynValue(name, value);
3233

    
3234
    }
3235

    
3236
    /*
3237
     * (non-Javadoc)
3238
     *
3239
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3240
     */
3241
    @Override
3242
    public Set getMetadataChildren() {
3243
        return this.metadataChildren;
3244
    }
3245

    
3246
    /*
3247
     * (non-Javadoc)
3248
     *
3249
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3250
     */
3251
    @Override
3252
    public String getMetadataName() {
3253
        return this.provider.getProviderName();
3254
    }
3255

    
3256
    public FeatureTypeManager getFeatureTypeManager() {
3257
        return this.featureTypeManager;
3258
    }
3259

    
3260
    @Override
3261
    public long getFeatureCount() throws DataException {
3262
        if (featureCount == null) {
3263
            featureCount = this.provider.getFeatureCount();
3264
        }
3265
        if (this.isEditing()) {
3266
            if (this.isAppending()) {
3267
                try {
3268
                    throw new IllegalStateException();
3269
                } catch (IllegalStateException e) {
3270
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND", e);
3271
                }
3272
                return -1;
3273
            } else {
3274
                return featureCount
3275
                        + this.featureManager.getDeltaSize();
3276
            }
3277
        }
3278
        return featureCount;
3279
    }
3280

    
3281
    private Long getTemporalOID() {
3282
        return this.temporalOid++;
3283
    }
3284

    
3285
    @Override
3286
    public FeatureType getProviderFeatureType(String featureTypeId) {
3287
        if (featureTypeId == null) {
3288
            return this.defaultFeatureType;
3289
        }
3290
        FeatureType type;
3291
        Iterator iter = this.featureTypes.iterator();
3292
        while (iter.hasNext()) {
3293
            type = (FeatureType) iter.next();
3294
            if (type.getId().equals(featureTypeId)) {
3295
                return type;
3296
            }
3297
        }
3298
        return null;
3299
    }
3300

    
3301
    @Override
3302
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3303
        return ((DefaultFeature) feature).getData();
3304
    }
3305

    
3306
    @Override
3307
    public DataStore getStore() {
3308
        return this;
3309
    }
3310

    
3311
    @Override
3312
    public FeatureStore getFeatureStore() {
3313
        return this;
3314
    }
3315

    
3316
    @Override
3317
    public void createCache(String name, DynObject parameters)
3318
            throws DataException {
3319
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3320
        if (cache == null) {
3321
            throw new CreateException("FeaureCacheProvider", null);
3322
        }
3323
        cache.apply(this, provider);
3324
        provider = cache;
3325

    
3326
        featureCount = null;
3327
    }
3328

    
3329
    @Override
3330
    public FeatureCache getCache() {
3331
        return cache;
3332
    }
3333

    
3334
    @Override
3335
    public void clear() {
3336
        if (metadata != null) {
3337
            metadata.clear();
3338
        }
3339
    }
3340

    
3341
    @Override
3342
    public String getName() {
3343
        if (this.provider != null) {
3344
            return this.provider.getName();
3345
        }
3346
        if (this.parameters instanceof HasAFile) {
3347
            return FilenameUtils.getName(((HasAFile) this.parameters).getFile().getName());
3348
        }
3349
        return "unknow";
3350
    }
3351

    
3352
    @Override
3353
    public String getFullName() {
3354
        try {
3355
            if (this.provider != null) {
3356
                return this.provider.getFullName();
3357
            }
3358
            if (this.parameters instanceof HasAFile) {
3359
                return (((HasAFile) this.parameters).getFile().getAbsolutePath());
3360
            }
3361
            return null;
3362
        } catch (Throwable th) {
3363
            return null;
3364
        }
3365
    }
3366

    
3367
    @Override
3368
    public String getProviderName() {
3369
        if (this.provider != null) {
3370
            return this.provider.getProviderName();
3371
        }
3372
        if (this.parameters != null) {
3373
            return this.parameters.getDataStoreName();
3374
        }
3375
        return null;
3376

    
3377
    }
3378

    
3379
    @Override
3380
    public boolean isKnownEnvelope() {
3381
        return this.provider.isKnownEnvelope();
3382
    }
3383

    
3384
    @Override
3385
    public boolean hasRetrievedFeaturesLimit() {
3386
        return this.provider.hasRetrievedFeaturesLimit();
3387
    }
3388

    
3389
    @Override
3390
    public int getRetrievedFeaturesLimit() {
3391
        return this.provider.getRetrievedFeaturesLimit();
3392
    }
3393

    
3394
    @Override
3395
    public Interval getInterval() {
3396
        if (this.timeSupport != null) {
3397
            return this.timeSupport.getInterval();
3398
        }
3399
        try {
3400
            FeatureType type = this.getDefaultFeatureType();
3401
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3402
            if (attr != null) {
3403
                Interval interval = attr.getInterval();
3404
                if (interval != null) {
3405
                    return interval;
3406
                }
3407
            }
3408
        } catch (DataException ex) {
3409
        }
3410
        return this.provider.getInterval();
3411
    }
3412

    
3413
    @Override
3414
    public Collection getTimes() {
3415
        if (this.timeSupport != null) {
3416
            return this.timeSupport.getTimes();
3417
        }
3418
        return this.provider.getTimes();
3419
    }
3420

    
3421
    @Override
3422
    public Collection getTimes(Interval interval) {
3423
        if (this.timeSupport != null) {
3424
            return this.timeSupport.getTimes(interval);
3425
        }
3426
        return this.provider.getTimes(interval);
3427
    }
3428

    
3429
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3430
        if (this.isEditing()) {
3431
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' while store is editing.");
3432
        }
3433
        if (!this.transforms.isEmpty()) {
3434
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "' if has transforms.");
3435
        }
3436
        FeatureType ft = this.defaultFeatureType;
3437
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3438
        if (attr == null) {
3439
            throw new RuntimeException("Can't add time support over attribute '" + timeSupport.getAttributeName() + "', this attribute don't exists.");
3440
        }
3441
        EditableFeatureType eft = ft.getEditable();
3442
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3443
        if (attr != null) {
3444
            if (!(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport)) {
3445
                throw new RuntimeException("Can't add time support, attribute '" + timeSupport.getAttributeName() + "'already exists.");
3446
            }
3447
            eft.remove(attr.getName());
3448
        }
3449
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3450
                timeSupport.getAttributeName(),
3451
                timeSupport.getDataType()
3452
        );
3453
        attrTime.setIsTime(true);
3454
        attrTime.setFeatureAttributeEmulator(timeSupport);
3455
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3456
        this.defaultFeatureType = eft.getNotEditableCopy();
3457

    
3458
        this.timeSupport = timeSupport;
3459
    }
3460

    
3461
    @Override
3462
    @SuppressWarnings("CloneDoesntCallSuperClone")
3463
    public Object clone() throws CloneNotSupportedException {
3464

    
3465
        DataStoreParameters dsp = getParameters();
3466

    
3467
        DefaultFeatureStore cloned_store = null;
3468

    
3469
        try {
3470
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3471
                    openStore(this.getProviderName(), dsp);
3472
            if (transforms != null) {
3473
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3474
                cloned_store.transforms.setStoreForClone(cloned_store);
3475
            }
3476
        } catch (Exception e) {
3477
            throw new CloneException(e);
3478
        }
3479
        return cloned_store;
3480

    
3481
    }
3482

    
3483
    @Override
3484
    public Feature getFeature(DynObject dynobject) {
3485
        if (dynobject instanceof DynObjectFeatureFacade) {
3486
            Feature f = ((DynObjectFeatureFacade) dynobject).getFeature();
3487
            return f;
3488
        }
3489
        return null;
3490
    }
3491

    
3492
    @Override
3493
    public Iterator iterator() {
3494
        FeatureSet fset = null;
3495
        try {
3496
            fset = this.getFeatureSet();
3497
            return fset.fastIterator();
3498
        } catch (DataException ex) {
3499
            throw new RuntimeException(ex);
3500
        } finally {
3501
            DisposeUtils.disposeQuietly(fset);
3502
        }
3503
    }
3504

    
3505
    @Override
3506
    public long size64() {
3507
        FeatureSet fset = null;
3508
        try {
3509
            fset = this.getFeatureSet();
3510
            return fset.getSize();
3511
        } catch (DataException ex) {
3512
            throw new RuntimeException(ex);
3513
        } finally {
3514
            DisposeUtils.disposeQuietly(fset);
3515
        }
3516
    }
3517

    
3518
    @Override
3519
    public ExpressionBuilder createExpressionBuilder() {
3520
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3521
        return builder;
3522
    }
3523

    
3524
    @Override
3525
    public ExpressionBuilder createExpression() {
3526
        return createExpressionBuilder();
3527
    }
3528

    
3529
    public FeatureSet features() throws DataException {
3530
        // This is to avoid jython to create a property with this name
3531
        // to access method getFeatures.
3532
        return this.getFeatureSet();
3533
    }
3534

    
3535
    @Override
3536
    public DataStoreProviderFactory getProviderFactory() {
3537
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3538
        return factory;
3539
    }
3540

    
3541
    @Override
3542
    public void useCache(String providerName, DynObject parameters) throws DataException {
3543
        throw new UnsupportedOperationException();
3544
    }
3545

    
3546
    @Override
3547
    public boolean isBroken() {
3548
        return this.state.isBroken();
3549
    }
3550

    
3551
    @Override
3552
    public Throwable getBreakingsCause() {
3553
        return this.state.getBreakingsCause();
3554
    }
3555

    
3556
    @Override
3557
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3558
        FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3559
        if (!factory.supportNumericOID()) {
3560
            return null;
3561
        }
3562
        SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3563
        return wrappedIndex;
3564
    }
3565

    
3566
    @Override
3567
    public FeatureReference getFeatureReference(String code) {
3568
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3569
        return featureReference;
3570
    }
3571

    
3572
    @Override
3573
    public long getPendingChangesCount() {
3574
        if (this.featureManager == null) {
3575
            return 0;
3576
        }
3577
        return this.featureManager.getPendingChangesCount();
3578
    }
3579

    
3580
    private ResourcesStorage resourcesStorage;
3581

    
3582
    @Override
3583
    public ResourcesStorage getResourcesStorage() {
3584
        if (this.resourcesStorage != null) {
3585
            return this.resourcesStorage;
3586
        }
3587
        ResourcesStorage theResourcesStorage;
3588
        try {
3589
            theResourcesStorage = this.provider.getResourcesStorage();
3590
            if (theResourcesStorage != null) {
3591
                this.resourcesStorage = theResourcesStorage;
3592
                return theResourcesStorage;
3593
            }
3594
        } catch (Throwable th) {
3595

    
3596
        }
3597
        try {
3598
            DataServerExplorer explorer = this.getExplorer();
3599
            if (explorer == null) {
3600
                return null;
3601
            }
3602
            theResourcesStorage = explorer.getResourcesStorage(this);
3603
            explorer.dispose();
3604
            this.resourcesStorage = theResourcesStorage;
3605
            return theResourcesStorage;
3606
        } catch (Exception ex) {
3607
            LOGGER.trace("Can't create resources storage", ex);
3608
            return null;
3609
        }
3610
    }
3611

    
3612
    @Override
3613
    public StoresRepository getStoresRepository() {
3614
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3615
        StoresRepository localRepository = this.provider.getStoresRepository();
3616
        if (localRepository == null) {
3617
            return mainRepository;
3618
        }
3619
        StoresRepository repository = new BaseStoresRepository(this.getName());
3620
        repository.addRepository(localRepository);
3621
        repository.addRepository(mainRepository);
3622
        return repository;
3623
    }
3624

    
3625
    @Override
3626
    public Feature getSampleFeature() {
3627
        Feature sampleFeature;
3628
        try {
3629
            FeatureSelection theSelection = this.getFeatureSelection();
3630
            if (theSelection != null && !theSelection.isEmpty()) {
3631
                sampleFeature = theSelection.first();
3632
            } else {
3633
                sampleFeature = this.first();
3634
            }
3635
            if (sampleFeature == null) {
3636
                sampleFeature = this.createNewFeature();
3637
            }
3638
        } catch (DataException ex) {
3639
            return null;
3640
        }
3641
        return sampleFeature;
3642
    }
3643

    
3644
    @Override
3645
    public boolean supportReferences() {
3646
        try {
3647
            return this.getDefaultFeatureType().supportReferences();
3648
        } catch (Exception ex) {
3649
            return false;
3650
        }
3651
    }
3652

    
3653
    @Override
3654
    public boolean isTemporary() {
3655
        if (this.provider == null) {
3656
            return true;
3657
        }
3658
        return this.provider.isTemporary();
3659
    }
3660

    
3661
    public FeatureType getOriginalFeatureType(FeatureType featureType) {
3662
        // FIXME this don't work for Store.fType.size() > 1
3663
        FeatureTypeManager manager = this.featureTypeManager;
3664
        if (manager == null) {
3665
            return null;
3666
        }
3667
        FeatureType originalFeatureType = manager.getOriginalFeatureType();
3668
        if (originalFeatureType == null) {
3669
            return null;
3670
        }
3671
        return originalFeatureType.getCopy();
3672
    }
3673

    
3674
    @Override
3675
    public Object getProperty(String name) {
3676
        if (this.propertiesSupportHelper == null) {
3677
            return null;
3678
        }
3679
        return this.propertiesSupportHelper.getProperty(name);
3680
    }
3681

    
3682
    @Override
3683
    public void setProperty(String name, Object value) {
3684
        if (this.propertiesSupportHelper == null) {
3685
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3686
        }
3687
        this.propertiesSupportHelper.setProperty(name, value);
3688
    }
3689

    
3690
    @Override
3691
    public Map<String, Object> getProperties() {
3692
        if (this.propertiesSupportHelper == null) {
3693
            return Collections.EMPTY_MAP;
3694
        }
3695
        return this.propertiesSupportHelper.getProperties();
3696
    }
3697

    
3698
    @Override
3699
    public Feature getOriginalFeature(FeatureReference id) {
3700
        if (this.featureManager == null) {
3701
            return null;
3702
        }
3703
        return featureManager.getOriginal(id);
3704
    }
3705

    
3706
    @Override
3707
    public Feature getOriginalFeature(Feature feature) {
3708
        if (feature == null) {
3709
            return null;
3710
        }
3711
        return getOriginalFeature(feature.getReference());
3712
    }
3713

    
3714
    @Override
3715
    public boolean isFeatureModified(FeatureReference id) {
3716
        if (this.featureManager == null) {
3717
            return false;
3718
        }
3719
        return featureManager.isFeatureModified(id);
3720
    }
3721

    
3722
    @Override
3723
    public boolean isFeatureModified(Feature feature) {
3724
        if (feature == null) {
3725
            return false;
3726
        }
3727
        return isFeatureModified(feature.getReference());
3728
    }
3729

    
3730
    @Override
3731
    public void setTransaction(DataTransaction transaction) {
3732
        this.transaction = transaction;
3733
        if (transaction instanceof DataTransactionServices) {
3734
            this.provider.setTransaction((DataTransactionServices) transaction);
3735
        }
3736
    }
3737

    
3738
    @Override
3739
    public DataTransaction getTransaction() {
3740
        return transaction;
3741
    }
3742

    
3743
    @Override
3744
    public String toString() {
3745
        try {
3746
            return String.format("%s %x %s", this.getClass().getSimpleName(), this.hashCode(), this.getFullName());
3747
        } catch (Exception e) {
3748
            return super.toString();
3749
        }
3750
    }
3751

    
3752
    public String createUniqueID() {
3753
        UUID x = UUID.randomUUID();
3754
        String s = x.toString();
3755
        return s;
3756
    }
3757

    
3758
}