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

History | View | Annotate | Download (133 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_BASIC;
76
import static org.gvsig.fmap.dal.feature.Feature.CHECK_REQUIREDS;
77
import static org.gvsig.fmap.dal.feature.Feature.CHECK_RULES_AT_EDITING;
78
import static org.gvsig.fmap.dal.feature.Feature.CHECK_RULES_AT_FINISH;
79
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
80
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
81
import org.gvsig.fmap.dal.feature.FeatureCache;
82
import org.gvsig.fmap.dal.feature.FeatureIndex;
83
import org.gvsig.fmap.dal.feature.FeatureIndexes;
84
import org.gvsig.fmap.dal.feature.FeatureLocks;
85
import org.gvsig.fmap.dal.feature.FeatureQuery;
86
import org.gvsig.fmap.dal.feature.FeatureReference;
87
import org.gvsig.fmap.dal.feature.FeatureReferenceSelection;
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
        if (!this.ignoreDALResource) {
331
            loadDALFile();
332

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

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

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

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

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

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

    
387
    public FeatureManager getFeatureManager() {
388
        return this.featureManager;
389
    }
390

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

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

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

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

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

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

    
480
        this.featureManager = null;
481
        this.spatialManager = null;
482

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

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

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

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

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

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

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

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

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

    
631
        }
632

    
633
        if (evaluatedAttr.isEmpty()) {
634
            evaluatedAttr = null;
635
        }
636

    
637
        state.set("evaluatedAttributes", evaluatedAttr);
638
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
639

    
640
    }
641

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

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

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

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

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

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

    
754
                }
755

    
756
            }
757
        } catch (Throwable th) {
758
            state.setBreakingsCause(th);
759
        }
760

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

    
765
            if (defaultFeatureType == null
766
                    || defaultFeatureType.getId() == null
767
                    || !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
768

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

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

    
793
    public DataStoreProviderServices getStoreProviderServices() {
794
        return this;
795
    }
796

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

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

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

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

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

    
823
            definition.addDynFieldString("defaultFeatureTypeId")
824
                    .setMandatory(true).setPersistent(true);
825
        }
826
    }
827

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

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

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

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

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

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

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

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

    
916
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
917
    }
918

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

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

    
932
    }
933

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1051
    }
1052

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

    
1058
    @Override
1059
    public void beginComplexNotification() {
1060
        this.delegateObservable.beginComplexNotification();
1061

    
1062
    }
1063

    
1064
    @Override
1065
    public void endComplexNotification() {
1066
        this.delegateObservable.endComplexNotification();
1067

    
1068
    }
1069

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

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

    
1084
    @Override
1085
    public void deleteObservers() {
1086
        this.delegateObservable.deleteObservers();
1087

    
1088
    }
1089

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

    
1108
        } else if (observable instanceof FeatureStoreProvider) {
1109
            if (observable == this.provider) {
1110

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

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

    
1127
    private long currentVersionOfUpdate() {
1128
        return this.versionOfUpdate;
1129
    }
1130

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

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

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

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

    
1163
        if (featureTypeManager != null) {
1164
            DisposeUtils.disposeQuietly(featureTypeManager);
1165
            featureTypeManager = null;
1166

    
1167
        }
1168

    
1169
        // TODO implementar un dispose para estos dos
1170
        featureManager = null;
1171
        spatialManager = null;
1172

    
1173
        featureCount = null;
1174

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

    
1179
        this.editingSessionCode = null;
1180
    }
1181

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

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

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

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

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

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

    
1275
    private void invalidateIndexes() {
1276
        setIndexesValidStatus(false);
1277
    }
1278

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

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

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

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

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

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

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

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

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

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

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

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

    
1414
        }
1415
    }
1416

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

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

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

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

    
1484
            //Update the featureManager and the spatialManager
1485
            featureManager.delete(feature);
1486
            spatialManager.deleteFeature(feature);
1487

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

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

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

    
1517
    private static EditableFeature lastChangedFeature = null;
1518

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

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

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

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

    
1570
    synchronized public void doInsert(EditableFeature feature)
1571
            throws DataException {
1572
        checkIsOwnFeature(feature);
1573

    
1574
        waitForIndexes();
1575

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

    
1590
        featureManager.add(feature);
1591
        spatialManager.insertFeature(newFeature);
1592

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1991
    }
1992

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

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

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

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

    
2084
                case MODE_APPEND:
2085
                    this.provider.endAppend();
2086
                    exitEditingMode();
2087
                    invalidateIndexes();
2088
                    this.provider.beginAppend();
2089
                    hasInserts = false;
2090
                    break;
2091

    
2092
                case MODE_FULLEDIT:
2093
                    if (hasStrongChanges && !this.allowWrite()) {
2094
                        throw new WriteNotAllowedException(getName());
2095
                    }
2096
                    // FIXME: OOhh!!!! no se disparan eventos, VCSGis no se entera de estos cambios.
2097
                    if (hasStrongChanges) {
2098
                        validateFeaturesAtFinishEditing();
2099
                        provider.performChanges(featureManager.getDeleted(),
2100
                                featureManager.getInserted(),
2101
                                featureManager.getUpdated(),
2102
                                removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2103
                    }
2104
                    invalidateIndexes();
2105
                    featureManager = new FeatureManager(this);
2106
                    featureTypeManager = new FeatureTypeManager(this);
2107
                    spatialManager = new SpatialManager(this, provider.getEnvelope());
2108

    
2109
                    commands
2110
                            = new DefaultFeatureCommandsStack(this, featureManager,
2111
                                    spatialManager, featureTypeManager);
2112
                    featureCount = null;
2113
                    hasStrongChanges = false;
2114
                    hasInserts = false;
2115
                    break;
2116
            }
2117
        } catch (Exception e) {
2118
            throw new FinishEditingException(e);
2119
        }
2120
    }
2121

    
2122
    @Override
2123
    synchronized public boolean canCommitChanges() throws DataException {
2124
        if (!this.allowWrite()) {
2125
            return false;
2126
        }
2127
        switch (mode) {
2128
            default:
2129
            case MODE_QUERY:
2130
                return false;
2131

    
2132
            case MODE_APPEND:
2133
                return true;
2134

    
2135
            case MODE_FULLEDIT:
2136
                List types = this.getFeatureTypes();
2137
                for (int i = 0; i < types.size(); i++) {
2138
                    Object type = types.get(i);
2139
                    if (type instanceof DefaultEditableFeatureType) {
2140
                        if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
2141
                            return false;
2142
                        }
2143
                    }
2144
                }
2145
                return true;
2146
        }
2147
    }
2148

    
2149
    @Override
2150
    public void beginEditingGroup(String description)
2151
            throws NeedEditingModeException {
2152
        checkInEditingMode();
2153
        commands.startComplex(description);
2154
    }
2155

    
2156
    @Override
2157
    public void endEditingGroup() throws NeedEditingModeException {
2158
        checkInEditingMode();
2159
        commands.endComplex();
2160
    }
2161

    
2162
    @Override
2163
    public boolean isAppendModeSupported() {
2164
        return this.provider.supportsAppendMode();
2165
    }
2166

    
2167
    @Override
2168
    public void export(DataServerExplorer explorer, String provider,
2169
            NewFeatureStoreParameters params, String name) throws DataException {
2170

    
2171
        if (this.getFeatureTypes().size() != 1) {
2172
            throw new NotYetImplemented(
2173
                    "export whith more than one type not yet implemented");
2174
        }
2175
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2176
        FeatureStore target = null;
2177
        FeatureSet features = null;
2178
        DisposableIterator iterator = null;
2179
        try {
2180
            FeatureType type = this.getDefaultFeatureType();
2181
            if ((params.getDefaultFeatureType() == null)
2182
                    || (params.getDefaultFeatureType().size() == 0)) {
2183
                params.setDefaultFeatureType(type.getEditable());
2184

    
2185
            }
2186
            explorer.add(provider, params, true);
2187
            DataManager manager = DALLocator.getDataManager();
2188

    
2189
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2190
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2191

    
2192
            target = (FeatureStore) manager.openStore(provider, openParams);
2193
            FeatureType targetType = target.getDefaultFeatureType();
2194

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

    
2226
    @Override
2227
    public void copyTo(final FeatureStore target) {
2228
        boolean finishEditingAtEnd = false;
2229
        try {
2230
            if (!target.isEditing() && !target.isAppending()) {
2231
                finishEditingAtEnd = true;
2232
                target.edit(MODE_APPEND);
2233
            }
2234
            this.accept((Object obj) -> {
2235
                Feature f_src = (Feature) obj;
2236
                EditableFeature f_dst = target.createNewFeature(f_src);
2237
                target.insert(f_dst);
2238
            });
2239
            if (finishEditingAtEnd) {
2240
                target.finishEditing();
2241
            }
2242

    
2243
        } catch (Exception ex) {
2244
            try {
2245
                if (finishEditingAtEnd) {
2246
                    target.cancelEditing();
2247
                }
2248
            } catch (Exception ex1) {
2249
            }
2250
            throw new RuntimeException("Can't copy store.", ex);
2251
        }
2252

    
2253
    }
2254

    
2255
    //
2256
    // ====================================================================
2257
    // Obtencion de datos
2258
    // getDataCollection, getFeatureCollection
2259
    //
2260
    @Override
2261
    public DataSet getDataSet() throws DataException {
2262
        checkNotInAppendMode();
2263
        FeatureQuery query
2264
                = new DefaultFeatureQuery(this.getDefaultFeatureType());
2265
        return new DefaultFeatureSet(this, query);
2266
    }
2267

    
2268
    @Override
2269
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2270
        checkNotInAppendMode();
2271
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2272
    }
2273

    
2274
    @Override
2275
    public void getDataSet(Observer observer) throws DataException {
2276
        checkNotInAppendMode();
2277
        this.getFeatureSet(null, observer);
2278
    }
2279

    
2280
    @Override
2281
    public void getDataSet(DataQuery dataQuery, Observer observer)
2282
            throws DataException {
2283
        checkNotInAppendMode();
2284
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2285
    }
2286

    
2287
    @Override
2288
    public FeatureSet getFeatureSet() throws DataException {
2289
        return this.getFeatureSet((FeatureQuery) null);
2290
    }
2291

    
2292
    @Override
2293
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2294
            throws DataException {
2295
        checkNotInAppendMode();
2296
        if (featureQuery == null) {
2297
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2298
        }
2299
        return new DefaultFeatureSet(this, featureQuery);
2300
    }
2301

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

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

    
2312
    @Override
2313
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2314
        return this.getFeatureSet(filter, null, true);
2315
    }
2316

    
2317
    @Override
2318
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2319
        return this.getFeatureSet(filter, sortBy, true);
2320
    }
2321

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

    
2328
    @Override
2329
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2330
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2331
        return this.getFeatureSet(query);
2332
    }
2333

    
2334
    @Override
2335
    public List<Feature> getFeatures(String filter) {
2336
        return this.getFeatures(filter, null, true);
2337
    }
2338

    
2339
    @Override
2340
    public List<Feature> getFeatures(String filter, String sortBy) {
2341
        return this.getFeatures(filter, sortBy, true);
2342
    }
2343

    
2344
    @Override
2345
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc) {
2346
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2347
        return this.getFeatures(query, 0);
2348
    }
2349

    
2350
    @Override
2351
    public List<Feature> getFeatures(Expression filter) {
2352
        return this.getFeatures(filter, null, true);
2353
    }
2354

    
2355
    @Override
2356
    public List<Feature> getFeatures(Expression filter, String sortBy) {
2357
        return this.getFeatures(filter, sortBy, true);
2358
    }
2359

    
2360
    @Override
2361
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc) {
2362
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2363
        return this.getFeatures(query, 0);
2364
    }
2365

    
2366
    @Override
2367
    public List<Feature> getFeatures(FeatureQuery query) {
2368
        return this.getFeatures(query, 0);
2369
    }
2370

    
2371
    @Override
2372
    public List<Feature> getFeatures(FeatureQuery query, int pageSize) {
2373
        try {
2374
            if (pageSize <= 0) {
2375
                pageSize = 100;
2376
            }
2377
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2378
            return pager.asList();
2379
        } catch (BaseException ex) {
2380
            throw new RuntimeException("Can't create the list of features.", ex);
2381
        }
2382
    }
2383

    
2384
    @Override
2385
    public List<Feature> getFeatures() {
2386
        return this.getFeatures(null, 0);
2387
    }
2388

    
2389
    @Override
2390
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2391
        return this.getFeatures64(null, 0);
2392
    }
2393

    
2394
    @Override
2395
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2396
        return this.getFeatures64(filter, null, true);
2397
    }
2398

    
2399
    @Override
2400
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc) {
2401
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2402
        return this.getFeatures64(query, 0);
2403
    }
2404

    
2405
    @Override
2406
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize) {
2407
        try {
2408
            if (pageSize <= 0) {
2409
                pageSize = 100;
2410
            }
2411
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2412
            return pager;
2413
        } catch (BaseException ex) {
2414
            throw new RuntimeException("Can't create the list of features.", ex);
2415
        }
2416
    }
2417

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

    
2423
    @Override
2424
    public Feature findFirst(String filter) throws DataException {
2425
        return this.findFirst(filter, (String) null, true);
2426
    }
2427

    
2428
    @Override
2429
    public Feature findFirst(String filter, String sortBy) throws DataException {
2430
        return this.findFirst(filter, sortBy, true);
2431
    }
2432

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

    
2439
    @Override
2440
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2441
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2442
        return findFirst(query);
2443
    }
2444

    
2445
    @Override
2446
    public Feature findFirst(Expression filter) throws DataException {
2447
        return this.findFirst(filter, (String) null, true);
2448
    }
2449

    
2450
    @Override
2451
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2452
        return this.findFirst(filter, sortBy, true);
2453
    }
2454

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

    
2461
    @Override
2462
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2463
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2464
        return findFirst(query);
2465
    }
2466

    
2467
    @Override
2468
    public Feature findFirst(FeatureQuery query) throws DataException {
2469
        if (query == null) {
2470
            query = this.createFeatureQuery();
2471
        } else {
2472
            query = query.getCopy();
2473
        }
2474
        query.setLimit(1);
2475
        final MutableObject<Feature> feature = new MutableObject<>();
2476
        try {
2477
            this.accept((Object obj) -> {
2478
                feature.setValue((Feature) obj);
2479
                throw new VisitCanceledException();
2480
            }, query);
2481
        } catch (VisitCanceledException ex) {
2482

    
2483
        } catch (DataException ex) {
2484
            throw ex;
2485
        } catch (Exception ex) {
2486
            throw new RuntimeException("", ex);
2487
        }
2488
        return feature.getValue();
2489
    }
2490

    
2491
    @Override
2492
    public void accept(Visitor visitor) throws BaseException {
2493
        this.accept(visitor, null);
2494
    }
2495

    
2496
    @Override
2497
    public void accept(Visitor visitor, DataQuery dataQuery)
2498
            throws BaseException {
2499
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2500
        try {
2501
            set.accept(visitor);
2502
        } finally {
2503
            set.dispose();
2504
        }
2505
    }
2506

    
2507
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2508
            throws DataException {
2509
        DefaultFeatureType fType
2510
                = (DefaultFeatureType) this.getFeatureType(featureQuery
2511
                        .getFeatureTypeId());
2512
        if (featureQuery.hasAttributeNames()
2513
                || featureQuery.hasConstantsAttributeNames()
2514
                || fType.hasRequiredFields()) {
2515
            if (featureQuery.hasGroupByColumns()) {
2516
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false);
2517
            } else {
2518
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2519
            }
2520
        }
2521
        return fType;
2522
    }
2523

    
2524
    @Override
2525
    public void getFeatureSet(Observer observer) throws DataException {
2526
        checkNotInAppendMode();
2527
        this.getFeatureSet(null, observer);
2528
    }
2529

    
2530
    @Override
2531
    public void getFeatureSet(FeatureQuery query, Observer observer)
2532
            throws DataException {
2533
        class LoadInBackGround implements Runnable {
2534

    
2535
            private final FeatureStore store;
2536
            private final FeatureQuery query;
2537
            private final Observer observer;
2538

    
2539
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2540
                    Observer observer) {
2541
                this.store = store;
2542
                this.query = query;
2543
                this.observer = observer;
2544
            }
2545

    
2546
            void notify(FeatureStoreNotification theNotification) {
2547
                observer.update(store, theNotification);
2548
            }
2549

    
2550
            @Override
2551
            public void run() {
2552
                FeatureSet set = null;
2553
                try {
2554
                    set = store.getFeatureSet(query);
2555
                    notify(new DefaultFeatureStoreNotification(store,
2556
                            FeatureStoreNotification.LOAD_FINISHED, set));
2557
                } catch (Exception e) {
2558
                    notify(new DefaultFeatureStoreNotification(store,
2559
                            FeatureStoreNotification.LOAD_FINISHED, e));
2560
                } finally {
2561
                    dispose(set);
2562
                }
2563
            }
2564
        }
2565

    
2566
        checkNotInAppendMode();
2567
        if (query == null) {
2568
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2569
        }
2570
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2571
        Thread thread = new Thread(task, "Load Feature Set in background");
2572
        thread.start();
2573
    }
2574

    
2575
    @Override
2576
    public Feature getFeatureByReference(FeatureReference reference)
2577
            throws DataException {
2578
        checkNotInAppendMode();
2579
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2580
        FeatureType featureType;
2581
        if (ref.getFeatureTypeId() == null) {
2582
            featureType = this.getDefaultFeatureType();
2583
        } else {
2584
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2585
        }
2586
        return this.getFeatureByReference(reference, featureType);
2587
    }
2588

    
2589
    @Override
2590
    public Feature getFeatureByReference(FeatureReference reference,
2591
            FeatureType featureType) throws DataException {
2592
        checkNotInAppendMode();
2593
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2594
        if (this.mode == MODE_FULLEDIT) {
2595
            Feature f = featureManager.get(reference, this, featureType);
2596
            if (f != null) {
2597
                return f;
2598
            }
2599
        }
2600

    
2601
        FeatureType sourceFeatureType = featureType;
2602
        if (!this.transforms.isEmpty()) {
2603
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2604
        }
2605
        // TODO comprobar que el id es de este store
2606

    
2607
        DefaultFeature feature
2608
                = new DefaultFeature(this,
2609
                        this.provider.getFeatureProviderByReference(
2610
                                (FeatureReferenceProviderServices) reference, sourceFeatureType));
2611

    
2612
        if (!this.transforms.isEmpty()) {
2613
            return this.transforms.applyTransform(feature, featureType);
2614
        }
2615
        return feature;
2616
    }
2617

    
2618
    //
2619
    // ====================================================================
2620
    // Gestion de features
2621
    //
2622
    private FeatureType fixFeatureType(DefaultFeatureType type)
2623
            throws DataException {
2624
        FeatureType original = this.getDefaultFeatureType();
2625

    
2626
        if ((type == null) || type.equals(original)) {
2627
            return original;
2628
        } else {
2629
            if (!type.isSubtypeOf(original)) {
2630
                Iterator iter = this.getFeatureTypes().iterator();
2631
                FeatureType tmpType;
2632
                boolean found = false;
2633
                while (iter.hasNext()) {
2634
                    tmpType = (FeatureType) iter.next();
2635
                    if (type.equals(tmpType)) {
2636
                        return type;
2637

    
2638
                    } else if (type.isSubtypeOf(tmpType)) {
2639
                        found = true;
2640
                        original = tmpType;
2641
                        break;
2642
                    }
2643

    
2644
                }
2645
                if (!found) {
2646
                    throw new IllegalFeatureTypeException(getName());
2647
                }
2648
            }
2649
        }
2650

    
2651
        // Checks that type has all fields of pk
2652
        // else add the missing attributes at the end.
2653
        if (!original.hasOID()) {
2654
            // Gets original pk attributes
2655
            DefaultEditableFeatureType edOriginal
2656
                    = (DefaultEditableFeatureType) original.getEditable();
2657
            FeatureAttributeDescriptor orgAttr;
2658
            Iterator edOriginalIter = edOriginal.iterator();
2659
            while (edOriginalIter.hasNext()) {
2660
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2661
                if (!orgAttr.isPrimaryKey()) {
2662
                    edOriginalIter.remove();
2663
                }
2664
            }
2665

    
2666
            // Checks if all pk attributes are in type
2667
            Iterator typeIterator;
2668
            edOriginalIter = edOriginal.iterator();
2669
            FeatureAttributeDescriptor attr;
2670
            while (edOriginalIter.hasNext()) {
2671
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2672
                typeIterator = type.iterator();
2673
                while (typeIterator.hasNext()) {
2674
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2675
                    if (attr.getName().equals(orgAttr.getName())) {
2676
                        edOriginalIter.remove();
2677
                        break;
2678
                    }
2679
                }
2680
            }
2681

    
2682
            // add missing pk attributes if any
2683
            if (edOriginal.size() > 0) {
2684
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2685
                DefaultEditableFeatureType edType
2686
                        = (DefaultEditableFeatureType) original.getEditable();
2687
                edType.clear();
2688
                edType.addAll(type);
2689
                edType.addAll(edOriginal);
2690
                if (!isEditable) {
2691
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2692
                }
2693
            }
2694

    
2695
        }
2696

    
2697
        return type;
2698
    }
2699

    
2700
    private void validateFeaturesAtFinishEditing() throws ValidateFeaturesException {
2701
        try {
2702
            checkInEditingMode();
2703
            FeatureType type = this.getDefaultFeatureTypeQuietly();
2704
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
2705

    
2706
            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS : 0;
2707
            checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
2708
            if (checks == 0) {
2709
                return;
2710
            }
2711

    
2712
            Iterator<EditableFeature> features = new ChainedIterator<>(
2713
                    featureManager.getInsertedFeatures(),
2714
                    featureManager.getUpdatedFeatures()
2715
            );
2716
            while (features.hasNext()) {
2717
                EditableFeature feature = features.next();
2718
                rules.validate(feature, checks);
2719
            }
2720
        } catch (Exception ex) {
2721
            throw new ValidateFeaturesException(this.getName(), ex);
2722
        }
2723
    }
2724

    
2725
    @Override
2726
    public FeatureType getDefaultFeatureType() throws DataException {
2727
        try {
2728

    
2729
            if (isEditing()) {
2730
                FeatureType auxFeatureType
2731
                        = featureTypeManager.getType(defaultFeatureType.getId());
2732
                if (auxFeatureType != null) {
2733
                    return avoidEditable(auxFeatureType);
2734
                }
2735
            }
2736
            FeatureType type = this.transforms.getDefaultFeatureType();
2737
            if (type != null) {
2738
                return avoidEditable(type);
2739
            }
2740

    
2741
            return avoidEditable(defaultFeatureType);
2742

    
2743
        } catch (Exception e) {
2744
            throw new GetFeatureTypeException(e, getName());
2745
        }
2746
    }
2747

    
2748
    @Override
2749
    public FeatureType getDefaultFeatureTypeQuietly() {
2750
        try {
2751
            return this.getDefaultFeatureType();
2752
        } catch (Exception ex) {
2753
            return null;
2754
        }
2755
    }
2756

    
2757
    private FeatureType avoidEditable(FeatureType ft) {
2758
        if (ft instanceof EditableFeatureType) {
2759
            return ((EditableFeatureType) ft).getNotEditableCopy();
2760
        } else {
2761
            return ft;
2762
        }
2763
    }
2764

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

    
2796
    public FeatureType getProviderDefaultFeatureType() {
2797
        return defaultFeatureType;
2798
    }
2799

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

    
2831
    public List getProviderFeatureTypes() throws DataException {
2832
        return Collections.unmodifiableList(this.featureTypes);
2833
    }
2834

    
2835
    @Override
2836
    public Feature createFeature(FeatureProvider data) throws DataException {
2837
        DefaultFeature feature = new DefaultFeature(this, data);
2838
        return feature;
2839
    }
2840

    
2841
    public Feature createFeature(FeatureProvider data, FeatureType type)
2842
            throws DataException {
2843
        // FIXME: falta por implementar
2844
        // Comprobar si es un subtipo del feature de data
2845
        // y construir un feature usando el subtipo.
2846
        // Probablemente requiera generar una copia del data.
2847
        throw new NotYetImplemented();
2848
    }
2849

    
2850
    @Override
2851
    public EditableFeature createNewFeature(FeatureType type,
2852
            Feature defaultValues) throws DataException {
2853
        try {
2854
            FeatureProvider data = createNewFeatureProvider(type);
2855
            DefaultEditableFeature feature
2856
                    = new DefaultEditableFeature(this, data);
2857
            feature.initializeValues(defaultValues);
2858
            data.setNew(true);
2859

    
2860
            return feature;
2861
        } catch (Exception e) {
2862
            throw new CreateFeatureException(e, getName());
2863
        }
2864
    }
2865

    
2866
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2867
            throws DataException {
2868
        type = this.fixFeatureType((DefaultFeatureType) type);
2869
        FeatureProvider data = this.provider.createFeatureProvider(type);
2870
        data.setNew(true);
2871
        if (type.hasOID() && (data.getOID() == null)) {
2872
            data.setOID(this.provider.createNewOID());
2873
        } else {
2874
            data.setOID(this.getTemporalOID());
2875
        }
2876
        return data;
2877

    
2878
    }
2879

    
2880
    @Override
2881
    public EditableFeature createNewFeature(FeatureType type,
2882
            boolean defaultValues) throws DataException {
2883
        try {
2884
            FeatureProvider data = createNewFeatureProvider(type);
2885
            DefaultEditableFeature feature
2886
                    = new DefaultEditableFeature(this, data);
2887
            if (defaultValues) {
2888
                feature.initializeValues();
2889
            }
2890
            return feature;
2891
        } catch (Exception e) {
2892
            throw new CreateFeatureException(e, getName());
2893
        }
2894
    }
2895

    
2896
    @Override
2897
    public EditableFeature createNewFeature(boolean defaultValues)
2898
            throws DataException {
2899
        return this.createNewFeature(this.getDefaultFeatureType(),
2900
                defaultValues);
2901
    }
2902

    
2903
    @Override
2904
    public EditableFeature createNewFeature() throws DataException {
2905
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2906
    }
2907

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

    
2916
    @Override
2917
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2918
        FeatureType ft = this.getDefaultFeatureType();
2919
        EditableFeature f = this.createNewFeature(ft, false);
2920
        f.copyFrom(defaultValues);
2921
        return f;
2922
    }
2923

    
2924
    @Override
2925
    public EditableFeatureType createFeatureType() {
2926
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2927
        return ftype;
2928
    }
2929

    
2930
    @Override
2931
    public EditableFeatureType createFeatureType(String id) {
2932
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2933
        return ftype;
2934
    }
2935

    
2936
    //
2937
    // ====================================================================
2938
    // Index related methods
2939
    //
2940
    @Override
2941
    public FeatureIndexes getIndexes() {
2942
        return this.indexes;
2943
    }
2944

    
2945
    @Override
2946
    public FeatureIndex createIndex(FeatureType featureType,
2947
            String attributeName, String indexName) throws DataException {
2948
        return createIndex(null, featureType, attributeName, indexName);
2949
    }
2950

    
2951
    @Override
2952
    public FeatureIndex createIndex(String indexTypeName,
2953
            FeatureType featureType, String attributeName, String indexName)
2954
            throws DataException {
2955

    
2956
        return createIndex(indexTypeName, featureType, attributeName,
2957
                indexName, false, null);
2958
    }
2959

    
2960
    @Override
2961
    public FeatureIndex createIndex(FeatureType featureType,
2962
            String attributeName, String indexName, Observer observer)
2963
            throws DataException {
2964
        return createIndex(null, featureType, attributeName, indexName,
2965
                observer);
2966
    }
2967

    
2968
    @Override
2969
    public FeatureIndex createIndex(String indexTypeName,
2970
            FeatureType featureType, String attributeName, String indexName,
2971
            final Observer observer) throws DataException {
2972

    
2973
        return createIndex(indexTypeName, featureType, attributeName,
2974
                indexName, true, observer);
2975
    }
2976

    
2977
    private FeatureIndex createIndex(String indexTypeName,
2978
            FeatureType featureType, String attributeName, String indexName,
2979
            boolean background, final Observer observer) throws DataException {
2980

    
2981
        checkNotInAppendMode();
2982
        FeatureIndexProviderServices index;
2983
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2984
                featureType, indexName,
2985
                featureType.getAttributeDescriptor(attributeName));
2986

    
2987
        try {
2988
            index.fill(background, observer);
2989
        } catch (FeatureIndexException e) {
2990
            throw new InitializeException(index.getName(), e);
2991
        }
2992

    
2993
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2994
        return index;
2995
    }
2996

    
2997
    //
2998
    // ====================================================================
2999
    // Transforms related methods
3000
    //
3001
    @Override
3002
    public FeatureStoreTransforms getTransforms() {
3003
        return this.transforms;
3004
    }
3005

    
3006
    @Override
3007
    public FeatureQuery createFeatureQuery() {
3008
        return new DefaultFeatureQuery(this.getName());
3009
    }
3010

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

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

    
3061
    @Override
3062
    public FeatureQuery createFeatureQuery(Expression filter) {
3063
        return this.createFeatureQuery(
3064
                filter,
3065
                (String) null,
3066
                true
3067
        );
3068
    }
3069

    
3070
    @Override
3071
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
3072
        if (StringUtils.isBlank(filter)) {
3073
            return this.createFeatureQuery(
3074
                    (Expression) null,
3075
                    sortBy,
3076
                    asc
3077
            );
3078
        } else {
3079
            return this.createFeatureQuery(
3080
                    ExpressionUtils.createExpression(filter),
3081
                    sortBy,
3082
                    asc
3083
            );
3084
        }
3085
    }
3086

    
3087
    @Override
3088
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
3089
        FeatureQuery query = null;
3090
        if (filter != null) {
3091
            query = this.createFeatureQuery();
3092
            query.setFilter(filter);
3093
        }
3094
        if (sortBy != null) {
3095
            if (query == null) {
3096
                query = this.createFeatureQuery();
3097
            }
3098
            query.getOrder().add(sortBy, asc);
3099
        }
3100

    
3101
        if (query != null) {
3102
            query.retrievesAllAttributes();
3103
        }
3104
        return query;
3105
    }
3106

    
3107
    @Override
3108
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3109
        if (StringUtils.isBlank(filter)) {
3110
            return this.createFeatureQuery(
3111
                    (Expression) null,
3112
                    sortBy,
3113
                    asc
3114
            );
3115
        } else {
3116
            return this.createFeatureQuery(
3117
                    ExpressionUtils.createExpression(filter),
3118
                    sortBy,
3119
                    asc
3120
            );
3121
        }
3122
    }
3123

    
3124
    @Override
3125
    public DataQuery createQuery() {
3126
        return createFeatureQuery();
3127
    }
3128

    
3129
    //
3130
    // ====================================================================
3131
    // UndoRedo related methods
3132
    //
3133
    @Override
3134
    public boolean canRedo() {
3135
        return commands.canRedo();
3136
    }
3137

    
3138
    @Override
3139
    public boolean canUndo() {
3140
        return commands.canUndo();
3141
    }
3142

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

    
3150
    @Override
3151
    public void undo(int num) throws UndoException {
3152
        for (int i = 0; i < num; i++) {
3153
            undo();
3154
        }
3155
    }
3156

    
3157
    //
3158
    // ====================================================================
3159
    // Metadata related methods
3160
    //
3161
    @Override
3162
    public Object getMetadataID() {
3163
        return this.provider.getSourceId();
3164
    }
3165

    
3166
    @Override
3167
    public void delegate(DynObject dynObject) {
3168
        this.metadata.delegate(dynObject);
3169
    }
3170

    
3171
    @Override
3172
    public DynClass getDynClass() {
3173
        return this.metadata.getDynClass();
3174
    }
3175

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

    
3203
    @Override
3204
    public boolean hasDynValue(String name) {
3205
        if (this.transforms.hasDynValue(name)) {
3206
            return true;
3207
        }
3208
        return this.metadata.hasDynValue(name);
3209
    }
3210

    
3211
    @Override
3212
    public boolean hasDynMethod(String name) {
3213
        return ((DynObject_v2) this.metadata).hasDynMethod(name);
3214
    }
3215

    
3216
    @Override
3217
    public void implement(DynClass dynClass) {
3218
        this.metadata.implement(dynClass);
3219
    }
3220

    
3221
    @Override
3222
    public Object invokeDynMethod(String name, Object[] args)
3223
            throws DynMethodException {
3224
        return this.metadata.invokeDynMethod(this, name, args);
3225
    }
3226

    
3227
    @Override
3228
    public Object invokeDynMethod(int code, Object[] args)
3229
            throws DynMethodException {
3230
        return this.metadata.invokeDynMethod(this, code, args);
3231
    }
3232

    
3233
    @Override
3234
    public void setDynValue(String name, Object value)
3235
            throws DynFieldNotFoundException {
3236
        if (this.transforms.hasDynValue(name)) {
3237
            this.transforms.setDynValue(name, value);
3238
            return;
3239
        }
3240
        this.metadata.setDynValue(name, value);
3241

    
3242
    }
3243

    
3244
    /*
3245
     * (non-Javadoc)
3246
     *
3247
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3248
     */
3249
    @Override
3250
    public Set getMetadataChildren() {
3251
        return this.metadataChildren;
3252
    }
3253

    
3254
    /*
3255
     * (non-Javadoc)
3256
     *
3257
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3258
     */
3259
    @Override
3260
    public String getMetadataName() {
3261
        return this.provider.getProviderName();
3262
    }
3263

    
3264
    public FeatureTypeManager getFeatureTypeManager() {
3265
        return this.featureTypeManager;
3266
    }
3267

    
3268
    @Override
3269
    public long getFeatureCount() throws DataException {
3270
        if (featureCount == null) {
3271
            featureCount = this.provider.getFeatureCount();
3272
        }
3273
        if (this.isEditing()) {
3274
            if (this.isAppending()) {
3275
                try {
3276
                    throw new IllegalStateException();
3277
                } catch (IllegalStateException e) {
3278
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND", e);
3279
                }
3280
                return -1;
3281
            } else {
3282
                return featureCount
3283
                        + this.featureManager.getDeltaSize();
3284
            }
3285
        }
3286
        return featureCount;
3287
    }
3288

    
3289
    private Long getTemporalOID() {
3290
        return this.temporalOid++;
3291
    }
3292

    
3293
    @Override
3294
    public FeatureType getProviderFeatureType(String featureTypeId) {
3295
        if (featureTypeId == null) {
3296
            return this.defaultFeatureType;
3297
        }
3298
        FeatureType type;
3299
        Iterator iter = this.featureTypes.iterator();
3300
        while (iter.hasNext()) {
3301
            type = (FeatureType) iter.next();
3302
            if (type.getId().equals(featureTypeId)) {
3303
                return type;
3304
            }
3305
        }
3306
        return null;
3307
    }
3308

    
3309
    @Override
3310
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3311
        return ((DefaultFeature) feature).getData();
3312
    }
3313

    
3314
    @Override
3315
    public DataStore getStore() {
3316
        return this;
3317
    }
3318

    
3319
    @Override
3320
    public FeatureStore getFeatureStore() {
3321
        return this;
3322
    }
3323

    
3324
    @Override
3325
    public void createCache(String name, DynObject parameters)
3326
            throws DataException {
3327
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3328
        if (cache == null) {
3329
            throw new CreateException("FeaureCacheProvider", null);
3330
        }
3331
        cache.apply(this, provider);
3332
        provider = cache;
3333

    
3334
        featureCount = null;
3335
    }
3336

    
3337
    @Override
3338
    public FeatureCache getCache() {
3339
        return cache;
3340
    }
3341

    
3342
    @Override
3343
    public void clear() {
3344
        if (metadata != null) {
3345
            metadata.clear();
3346
        }
3347
    }
3348

    
3349
    @Override
3350
    public String getName() {
3351
        if (this.provider != null) {
3352
            return this.provider.getName();
3353
        }
3354
        if (this.parameters instanceof HasAFile) {
3355
            return FilenameUtils.getName(((HasAFile) this.parameters).getFile().getName());
3356
        }
3357
        return "unknow";
3358
    }
3359

    
3360
    @Override
3361
    public String getFullName() {
3362
        try {
3363
            if (this.provider != null) {
3364
                return this.provider.getFullName();
3365
            }
3366
            if (this.parameters instanceof HasAFile) {
3367
                return (((HasAFile) this.parameters).getFile().getAbsolutePath());
3368
            }
3369
            return null;
3370
        } catch (Throwable th) {
3371
            return null;
3372
        }
3373
    }
3374

    
3375
    @Override
3376
    public String getProviderName() {
3377
        if (this.provider != null) {
3378
            return this.provider.getProviderName();
3379
        }
3380
        if (this.parameters != null) {
3381
            return this.parameters.getDataStoreName();
3382
        }
3383
        return null;
3384

    
3385
    }
3386

    
3387
    @Override
3388
    public boolean isKnownEnvelope() {
3389
        return this.provider.isKnownEnvelope();
3390
    }
3391

    
3392
    @Override
3393
    public boolean hasRetrievedFeaturesLimit() {
3394
        return this.provider.hasRetrievedFeaturesLimit();
3395
    }
3396

    
3397
    @Override
3398
    public int getRetrievedFeaturesLimit() {
3399
        return this.provider.getRetrievedFeaturesLimit();
3400
    }
3401

    
3402
    @Override
3403
    public Interval getInterval() {
3404
        if (this.timeSupport != null) {
3405
            return this.timeSupport.getInterval();
3406
        }
3407
        try {
3408
            FeatureType type = this.getDefaultFeatureType();
3409
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3410
            if (attr != null) {
3411
                Interval interval = attr.getInterval();
3412
                if (interval != null) {
3413
                    return interval;
3414
                }
3415
            }
3416
        } catch (DataException ex) {
3417
        }
3418
        return this.provider.getInterval();
3419
    }
3420

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

    
3429
    @Override
3430
    public Collection getTimes(Interval interval) {
3431
        if (this.timeSupport != null) {
3432
            return this.timeSupport.getTimes(interval);
3433
        }
3434
        return this.provider.getTimes(interval);
3435
    }
3436

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

    
3466
        this.timeSupport = timeSupport;
3467
    }
3468

    
3469
    @Override
3470
    @SuppressWarnings("CloneDoesntCallSuperClone")
3471
    public Object clone() throws CloneNotSupportedException {
3472

    
3473
        DataStoreParameters dsp = getParameters();
3474

    
3475
        DefaultFeatureStore cloned_store = null;
3476

    
3477
        try {
3478
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3479
                    openStore(this.getProviderName(), dsp);
3480
            if (transforms != null) {
3481
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3482
                cloned_store.transforms.setStoreForClone(cloned_store);
3483
            }
3484
        } catch (Exception e) {
3485
            throw new CloneException(e);
3486
        }
3487
        return cloned_store;
3488

    
3489
    }
3490

    
3491
    @Override
3492
    public Feature getFeature(DynObject dynobject) {
3493
        if (dynobject instanceof DynObjectFeatureFacade) {
3494
            Feature f = ((DynObjectFeatureFacade) dynobject).getFeature();
3495
            return f;
3496
        }
3497
        return null;
3498
    }
3499

    
3500
    @Override
3501
    public Iterator iterator() {
3502
        FeatureSet fset = null;
3503
        try {
3504
            fset = this.getFeatureSet();
3505
            return fset.fastIterator();
3506
        } catch (DataException ex) {
3507
            throw new RuntimeException(ex);
3508
        } finally {
3509
            DisposeUtils.disposeQuietly(fset);
3510
        }
3511
    }
3512

    
3513
    @Override
3514
    public long size64() {
3515
        FeatureSet fset = null;
3516
        try {
3517
            fset = this.getFeatureSet();
3518
            return fset.getSize();
3519
        } catch (DataException ex) {
3520
            throw new RuntimeException(ex);
3521
        } finally {
3522
            DisposeUtils.disposeQuietly(fset);
3523
        }
3524
    }
3525

    
3526
    @Override
3527
    public ExpressionBuilder createExpressionBuilder() {
3528
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3529
        return builder;
3530
    }
3531

    
3532
    @Override
3533
    public ExpressionBuilder createExpression() {
3534
        return createExpressionBuilder();
3535
    }
3536

    
3537
    public FeatureSet features() throws DataException {
3538
        // This is to avoid jython to create a property with this name
3539
        // to access method getFeatures.
3540
        return this.getFeatureSet();
3541
    }
3542

    
3543
    @Override
3544
    public DataStoreProviderFactory getProviderFactory() {
3545
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3546
        return factory;
3547
    }
3548

    
3549
    @Override
3550
    public void useCache(String providerName, DynObject parameters) throws DataException {
3551
        throw new UnsupportedOperationException();
3552
    }
3553

    
3554
    @Override
3555
    public boolean isBroken() {
3556
        return this.state.isBroken();
3557
    }
3558

    
3559
    @Override
3560
    public Throwable getBreakingsCause() {
3561
        return this.state.getBreakingsCause();
3562
    }
3563

    
3564
    @Override
3565
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3566
        FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3567
        if (!factory.supportNumericOID()) {
3568
            return null;
3569
        }
3570
        SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3571
        return wrappedIndex;
3572
    }
3573

    
3574
    @Override
3575
    public FeatureReference getFeatureReference(String code) {
3576
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3577
        return featureReference;
3578
    }
3579

    
3580
    @Override
3581
    public long getPendingChangesCount() {
3582
        if (this.featureManager == null) {
3583
            return 0;
3584
        }
3585
        return this.featureManager.getPendingChangesCount();
3586
    }
3587

    
3588
    private ResourcesStorage resourcesStorage;
3589

    
3590
    @Override
3591
    public ResourcesStorage getResourcesStorage() {
3592
        if (this.resourcesStorage != null) {
3593
            return this.resourcesStorage;
3594
        }
3595
        ResourcesStorage theResourcesStorage;
3596
        try {
3597
            theResourcesStorage = this.provider.getResourcesStorage();
3598
            if (theResourcesStorage != null) {
3599
                this.resourcesStorage = theResourcesStorage;
3600
                return theResourcesStorage;
3601
            }
3602
        } catch (Throwable th) {
3603

    
3604
        }
3605
        try {
3606
            DataServerExplorer explorer = this.getExplorer();
3607
            if (explorer == null) {
3608
                return null;
3609
            }
3610
            theResourcesStorage = explorer.getResourcesStorage(this);
3611
            explorer.dispose();
3612
            this.resourcesStorage = theResourcesStorage;
3613
            return theResourcesStorage;
3614
        } catch (Exception ex) {
3615
            LOGGER.trace("Can't create resources storage", ex);
3616
            return null;
3617
        }
3618
    }
3619

    
3620
    @Override
3621
    public StoresRepository getStoresRepository() {
3622
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3623
        StoresRepository localRepository = this.provider.getStoresRepository();
3624
        if (localRepository == null) {
3625
            return mainRepository;
3626
        }
3627
        StoresRepository repository = new BaseStoresRepository(this.getName());
3628
        repository.addRepository(localRepository);
3629
        repository.addRepository(mainRepository);
3630
        return repository;
3631
    }
3632

    
3633
    @Override
3634
    public Feature getSampleFeature() {
3635
        Feature sampleFeature;
3636
        try {
3637
            FeatureSelection theSelection = this.getFeatureSelection();
3638
            if (theSelection != null && !theSelection.isEmpty()) {
3639
                sampleFeature = theSelection.first();
3640
            } else {
3641
                sampleFeature = this.first();
3642
            }
3643
            if (sampleFeature == null) {
3644
                sampleFeature = this.createNewFeature();
3645
            }
3646
        } catch (DataException ex) {
3647
            return null;
3648
        }
3649
        return sampleFeature;
3650
    }
3651

    
3652
    @Override
3653
    public boolean supportReferences() {
3654
        try {
3655
            return this.getDefaultFeatureType().supportReferences();
3656
        } catch (Exception ex) {
3657
            return false;
3658
        }
3659
    }
3660

    
3661
    @Override
3662
    public boolean isTemporary() {
3663
        if (this.provider == null) {
3664
            return true;
3665
        }
3666
        return this.provider.isTemporary();
3667
    }
3668

    
3669
    public FeatureType getOriginalFeatureType(FeatureType featureType) {
3670
        // FIXME this don't work for Store.fType.size() > 1
3671
        FeatureTypeManager manager = this.featureTypeManager;
3672
        if (manager == null) {
3673
            return null;
3674
        }
3675
        FeatureType originalFeatureType = manager.getOriginalFeatureType();
3676
        if (originalFeatureType == null) {
3677
            return null;
3678
        }
3679
        return originalFeatureType.getCopy();
3680
    }
3681

    
3682
    @Override
3683
    public Object getProperty(String name) {
3684
        if (this.propertiesSupportHelper == null) {
3685
            return null;
3686
        }
3687
        return this.propertiesSupportHelper.getProperty(name);
3688
    }
3689

    
3690
    @Override
3691
    public void setProperty(String name, Object value) {
3692
        if (this.propertiesSupportHelper == null) {
3693
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3694
        }
3695
        this.propertiesSupportHelper.setProperty(name, value);
3696
    }
3697

    
3698
    @Override
3699
    public Map<String, Object> getProperties() {
3700
        if (this.propertiesSupportHelper == null) {
3701
            return Collections.EMPTY_MAP;
3702
        }
3703
        return this.propertiesSupportHelper.getProperties();
3704
    }
3705

    
3706
    @Override
3707
    public Feature getOriginalFeature(FeatureReference id) {
3708
        if (this.featureManager == null) {
3709
            return null;
3710
        }
3711
        return featureManager.getOriginal(id);
3712
    }
3713

    
3714
    @Override
3715
    public Feature getOriginalFeature(Feature feature) {
3716
        if (feature == null) {
3717
            return null;
3718
        }
3719
        return getOriginalFeature(feature.getReference());
3720
    }
3721

    
3722
    @Override
3723
    public boolean isFeatureModified(FeatureReference id) {
3724
        if (this.featureManager == null) {
3725
            return false;
3726
        }
3727
        return featureManager.isFeatureModified(id);
3728
    }
3729

    
3730
    @Override
3731
    public boolean isFeatureModified(Feature feature) {
3732
        if (feature == null) {
3733
            return false;
3734
        }
3735
        return isFeatureModified(feature.getReference());
3736
    }
3737

    
3738
    @Override
3739
    public void setTransaction(DataTransaction transaction) {
3740
        this.transaction = transaction;
3741
        if (transaction instanceof DataTransactionServices) {
3742
            this.provider.setTransaction((DataTransactionServices) transaction);
3743
        }
3744
    }
3745

    
3746
    @Override
3747
    public DataTransaction getTransaction() {
3748
        return transaction;
3749
    }
3750

    
3751
    @Override
3752
    public String toString() {
3753
        try {
3754
            return String.format("%s %x %s", this.getClass().getSimpleName(), this.hashCode(), this.getFullName());
3755
        } catch (Exception e) {
3756
            return super.toString();
3757
        }
3758
    }
3759

    
3760
    public String createUniqueID() {
3761
        UUID x = UUID.randomUUID();
3762
        String s = x.toString();
3763
        return s;
3764
    }
3765

    
3766
    @Override
3767
    public List<FeatureReference> getEditedFeatures() {
3768
        if( this.featureManager == null ) {
3769
            return Collections.EMPTY_LIST;
3770
        }
3771
        List<FeatureReference> references = this.featureManager.getAddedAndUpdatedFeatures();
3772
        if( references==null ) {
3773
            return Collections.EMPTY_LIST;
3774
        }
3775
        return references;
3776
    }
3777
    
3778
    public List<FeatureReference> getEditedFeaturesNotValidated() {
3779

    
3780
        try {
3781
            if (this.featureManager == null) {
3782
                return Collections.EMPTY_LIST;
3783
            }
3784
            
3785
            FeatureType type = this.getDefaultFeatureTypeQuietly();
3786
            DefaultFeatureRules rules = (DefaultFeatureRules) this.getDefaultFeatureType().getRules();
3787
            
3788
//            int checks = type.isCheckFeaturesAtFinishEditing() ? CHECK_REQUIREDS | CHECK_BASIC : 0;
3789
            int checks = CHECK_REQUIREDS | CHECK_BASIC;
3790
            if(type.isCheckFeaturesAtFinishEditing()){
3791
                checks = rules.isEmpty() ? checks : checks | CHECK_RULES_AT_FINISH;
3792
            }
3793
            if (checks == 0) {
3794
                return Collections.EMPTY_LIST;
3795
            }
3796
            List<FeatureReference> references = this.featureManager
3797
                    .getAddedAndUpdatedFeaturesNotValidated(rules, checks);
3798
            if (references == null) {
3799
                return Collections.EMPTY_LIST;
3800
            }
3801
            return references;
3802
        } catch (DataException ex) {
3803
            return null;
3804
        }
3805

    
3806
    }
3807

    
3808
}