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

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.info("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) {
1475
                throw new StoreDeleteEditableFeatureException(getName());
1476
            }
1477
            if (notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled()) {
1478
                return;
1479
            }
1480

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

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

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

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

    
1514
    private static EditableFeature lastChangedFeature = null;
1515

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

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

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

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

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

    
1571
        waitForIndexes();
1572

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1988
    }
1989

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

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

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

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

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

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

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

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

    
2123
            case MODE_APPEND:
2124
                return true;
2125

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

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

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

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

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

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

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

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

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

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

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

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

    
2244
    }
2245

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2686
        }
2687

    
2688
        return type;
2689
    }
2690

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

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

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

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

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

    
2732
            return avoidEditable(defaultFeatureType);
2733

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

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

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

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

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

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

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

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

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

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

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

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

    
2869
    }
2870

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3233
    }
3234

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

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

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

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

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

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

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

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

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

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

    
3325
        featureCount = null;
3326
    }
3327

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

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

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

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

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

    
3376
    }
3377

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

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

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

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

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

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

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

    
3457
        this.timeSupport = timeSupport;
3458
    }
3459

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

    
3464
        DataStoreParameters dsp = getParameters();
3465

    
3466
        DefaultFeatureStore cloned_store = null;
3467

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

    
3480
    }
3481

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3579
    private ResourcesStorage resourcesStorage;
3580

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3757
}