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

History | View | Annotate | Download (123 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

    
25
package org.gvsig.fmap.dal.feature.impl;
26

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

    
180
@SuppressWarnings("UseSpecificCatch")
181
public class DefaultFeatureStore extends AbstractDataStore implements
182
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
183

    
184
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
185

    
186
    private DataStoreParameters parameters = null;
187
    private FeatureSelection selection;
188
    private FeatureLocks locks;
189

    
190
    private DelegateWeakReferencingObservable delegateObservable =
191
        new DelegateWeakReferencingObservable(this);
192

    
193
    private FeatureCommandsStack commands;
194
    
195
    /*
196
    TODO: Sustituir estos tres manager por un EditingManager
197
    */
198
    private FeatureTypeManager featureTypeManager;
199
    private FeatureManager featureManager;
200
    private SpatialManager spatialManager;
201

    
202
    private FeatureType defaultFeatureType = null;
203
    private List<FeatureType> featureTypes = new ArrayList<>();
204

    
205
    private int mode = MODE_QUERY;
206
    private long versionOfUpdate = 0;
207
    private boolean hasStrongChanges = true;
208
    private boolean hasInserts = true;
209

    
210
    private DefaultDataManager dataManager = null;
211

    
212
    private FeatureStoreProvider provider = null;
213

    
214
    private DefaultFeatureIndexes indexes;
215

    
216
    private DefaultFeatureStoreTransforms transforms;
217

    
218
    /*friend*/ DelegatedDynObject metadata;
219

    
220
    private Set metadataChildren;
221

    
222
    private Long featureCount = null;
223

    
224
    private long temporalOid = 0;
225

    
226
    private FeatureCacheProvider cache;
227

    
228
    private final StateInformation state;
229

    
230
    private FeatureStoreTimeSupport timeSupport;
231
    
232
    private PropertiesSupportHelper propertiesSupportHelper;
233

    
234
    private class StateInformation extends HashMap<Object, Object> {
235

    
236
        private static final long serialVersionUID = 4109026189635185666L;
237

    
238
        private boolean broken;
239
        private Throwable breakingsCause;
240

    
241
        @SuppressWarnings("OverridableMethodCallInConstructor")
242
        public StateInformation() {
243
            this.clear();
244
        }
245

    
246
        @Override
247
        public void clear() {
248
            this.broken = false;
249
            this.breakingsCause = null;
250
            super.clear();
251
        }
252

    
253
        public boolean isBroken() {
254
            return this.broken;
255
        }
256

    
257
        public void broken() {
258
            this.broken = true;
259
        }
260

    
261
        public Throwable getBreakingsCause() {
262
            return this.breakingsCause;
263
        }
264

    
265
        public void setBreakingsCause(Throwable cause) {
266
            if( this.breakingsCause==null ) {
267
                this.breakingsCause = cause;
268
            }
269
            this.broken = true;
270
        }
271
    }
272

    
273

    
274

    
275
    /*
276
     * TODO:
277
     *
278
     * - Comprobar que solo se pueden a�adir reglas de validacion sobre un
279
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
280
     * featureType al que se le han cambiado las reglas de validacion cuando
281
     * hasStrongChanges=false.
282
     */
283

    
284
    public DefaultFeatureStore() {
285
        this.state = new StateInformation();
286
    }
287
    
288
    @Override
289
    protected DataManager getDataManager() {
290
        return this.dataManager;
291
    }
292

    
293
    @Override
294
    public void intialize(DataManager dataManager,
295
        DataStoreParameters parameters) throws InitializeException {
296

    
297
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
298

    
299
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
300
            FeatureStore.METADATA_DEFINITION_NAME,
301
            MetadataManager.METADATA_NAMESPACE
302
        );
303

    
304
        this.dataManager = (DefaultDataManager) dataManager;
305

    
306
        this.parameters = parameters;
307
        this.transforms = new DefaultFeatureStoreTransforms(this);
308
        try {
309
            indexes = new DefaultFeatureIndexes(this);
310
        } catch (DataException e) {
311
            throw new InitializeException(e);
312
        }
313

    
314
    }
315

    
316
    @Override
317
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
318
        this.provider = (FeatureStoreProvider) provider;
319
        this.delegate((DynObject) provider);
320
        this.metadataChildren = new HashSet();
321
        this.metadataChildren.add(provider);
322
        loadDALFile();
323
        
324
        // Habria que crear un metodo en el proveedor para que de prioidad
325
        // a los parametros frente a lo que se a leido en el fichero dal
326
        // DataStoreProvider arreglalo segun los parametros del usuario
327
        // fixFeatureTypeFromParameters
328
        this.provider.fixFeatureTypeFromParameters();
329
        try {
330
            if( defaultFeatureType!=null ) {
331
                FeatureAttributeDescriptor attrGeom = defaultFeatureType.getDefaultGeometryAttribute();
332
                if (attrGeom!=null) {
333
                    DefaultFeatureAttributeDescriptor gattr = (DefaultFeatureAttributeDescriptor) attrGeom;
334
                    IProjection srs = (IProjection) this.getDynValue(METADATA_CRS);
335
                    if( srs!=null && srs!=gattr.getSRS() ) {
336
                        gattr.setSRSForced(srs);
337
                    }
338
                }
339
            }
340
        } catch(Throwable th) {
341
            LOGGER.warn("Can't patch DAL file",th);
342
        }
343
    }
344

    
345
    @Override
346
    public DataStoreParameters getParameters() {
347
        if( this.parameters==null ) {
348
            LOGGER.warn("Store parametes are null");
349
        }
350
        return parameters;
351
    }
352

    
353
    @Override
354
    public int getMode() {
355
        return this.mode;
356
    }
357

    
358
    @Override
359
    public DataManager getManager() {
360
        return this.dataManager;
361
    }
362

    
363
    @Override
364
    public UnmodifiableBasicMap<String,DataStore> getChildren() {
365
        UnmodifiableBasicMap<String, DataStore> children = this.provider.getChildren();
366
        if( children == null ) {
367
            return UnmodifiableBasicMap.EMPTY_UNMODIFIABLEBASICMAP;
368
        }
369
        return children;
370
    }
371

    
372
    @Override
373
    public FeatureStoreProvider getProvider() {
374
        return this.provider;
375
    }
376

    
377
    public FeatureManager getFeatureManager() {
378
        return this.featureManager;
379
    }
380

    
381
    @Override
382
    public void setFeatureTypes(List types, FeatureType defaultType) {
383
        this.featureTypes = types;
384
        this.defaultFeatureType = defaultType;
385
    }
386

    
387
    public void open() throws OpenException {
388
        if (this.mode != MODE_QUERY) {
389
            // TODO: Se puede hacer un open estando en edicion ?
390
            try {
391
                throw new IllegalStateException();
392
            } catch(Exception ex) {
393
                LOGGER.warn("Opening a store in editing/append mode ("+this.getFullName()+").",ex);
394
            }
395
        }
396
        if( this.notifyChange(DataStoreNotification.BEFORE_OPEN).isCanceled() ) {
397
          return;
398
        }
399
        this.provider.open();
400
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
401
    }
402

    
403
    @Override
404
    public void refresh() throws OpenException, InitializeException {
405
        if (this.mode != MODE_QUERY) {
406
            throw new IllegalStateException();
407
        }
408
        if( this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH).isCanceled() ) {
409
          return;
410
        }
411
        if( state.isBroken() ) {
412
            this.load(state);
413
        } else {
414
            this.featureCount = null;
415
            this.provider.refresh();
416
        }
417
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
418
    }
419

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

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

    
465
        if (this.featureTypeManager != null) {
466
            this.featureTypeManager.dispose();
467
            this.featureTypeManager = null;
468
        }
469

    
470
        this.featureManager = null;
471
        this.spatialManager = null;
472

    
473
        this.parameters = null;
474
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
475
        if (delegateObservable != null) {
476
            this.delegateObservable.deleteObservers();
477
            this.delegateObservable = null;
478
        }
479
    }
480

    
481
    @Override
482
    public boolean allowWrite() {
483
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
484
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
485
            return false;
486
        }
487
        return this.provider.allowWrite();
488
    }
489

    
490
    @Override
491
    public boolean canWriteGeometry(int geometryType) throws DataException {
492
        return this.provider.canWriteGeometry(geometryType, 0);
493
    }
494

    
495
    @Override
496
    public DataServerExplorer getExplorer() throws ReadException,
497
        ValidateDataParametersException {
498
        if( this.state.isBroken() ) {
499
            try {
500
                return this.provider.getExplorer();
501
            } catch(Throwable th) {
502
                return null;
503
            }
504
        } else {
505
            return this.provider.getExplorer();
506
        }
507
    }
508

    
509
    /*
510
     * public Metadata getMetadata() throws MetadataNotFoundException {
511
     * // TODO:
512
     * // Si el provider devuelbe null habria que ver de construir aqui
513
     * // los metadatos basicos, como el Envelope y el SRS.
514
     *
515
     * // TODO: Estando en edicion el Envelope deberia de
516
     * // actualizarse usando el spatialManager
517
     * return this.provider.getMetadata();
518
     * }
519
     */
520

    
521
    @Override
522
    public Envelope getEnvelope() throws DataException {
523
        if (this.mode == MODE_FULLEDIT) {
524
                // Just in case another thread tries to write in the store
525
                synchronized (this) {
526
                        return this.spatialManager.getEnvelope();
527
                        }
528
        }
529
        if (hasDynValue(DataStore.METADATA_ENVELOPE)){
530
            return (Envelope)getDynValue(DataStore.METADATA_ENVELOPE);
531
        }
532
        Envelope envelope = this.provider.getEnvelope();
533
        if( envelope!=null ) {
534
            return envelope;
535
        }
536
        FeatureAttributeDescriptor attrdesc = this.getDefaultFeatureType().getDefaultGeometryAttribute();
537
        if( attrdesc == null || !attrdesc.isComputed() ) {
538
            return null;
539
        }
540
        final int index = attrdesc.getIndex();
541
        final MutableObject<Envelope> envelopeValue = new MutableObject<>();
542
        try {
543
            this.accept((Object obj) -> {
544
                Feature f = (Feature) obj;
545
                Geometry g =  (Geometry) f.get(index);
546
                if( g == null ) {
547
                    return;
548
                }
549
                if( envelopeValue.getValue()==null ) {
550
                    envelopeValue.setValue(g.getEnvelope());
551
                } else {
552
                    envelopeValue.getValue().add(g);
553
                }
554
            });
555
        } catch (Throwable th) {
556
            LOGGER.warn("Can't calculate envelope", th);
557
            return null;
558
        }
559
        return envelopeValue.getValue();
560
    }
561

    
562
    /**
563
     * @throws org.gvsig.fmap.dal.exception.DataException
564
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
565
     */
566
    @Override
567
    public IProjection getSRSDefaultGeometry() throws DataException {
568
        return this.getDefaultFeatureType().getDefaultSRS();
569
    }
570

    
571
    @Override
572
    public FeatureSelection createDefaultFeatureSelection()
573
        throws DataException {
574
        return new DefaultFeatureSelection(this);
575
    }
576

    
577
    @Override
578
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
579
        throws DataException {
580
        if (type.hasOID()) {
581
            return new DefaultFeatureProvider(type,
582
                this.provider.createNewOID());
583
        }
584
        return new DefaultFeatureProvider(type);
585
    }
586

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

    
622
        }
623

    
624
        if (evaluatedAttr.isEmpty()) {
625
            evaluatedAttr = null;
626
        }
627

    
628
        state.set("evaluatedAttributes", evaluatedAttr);
629
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
630

    
631
    }
632

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

    
672
    private void load(StateInformation state) {
673
        this.featureTypes = new ArrayList();
674
        this.defaultFeatureType = null;
675
        this.featureCount = null;
676

    
677
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
678
        try {
679
            intialize(dataManager, params);
680
        } catch(Throwable th) {
681
            state.setBreakingsCause(th);
682
        }
683

    
684
        try {
685
            DataStoreProvider prov = dataManager.createProvider(
686
                getStoreProviderServices(),
687
                params
688
            );
689
            setProvider(prov);
690
        } catch(Throwable th) {
691
            LOGGER.warn("Can't load store from state.", th);
692
            state.setBreakingsCause(th);
693
        }
694
        try {
695
            selection = (FeatureSelection) state.get("selection");
696
        } catch(Throwable th) {
697
            state.setBreakingsCause(th);
698
        }
699

    
700
        try {
701
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
702
            this.transforms.setFeatureStore(this);
703
            for( FeatureStoreTransform transform : this.transforms ) {
704
                try {
705
                    transform.setUp();
706
                } catch(Throwable th) {
707
                    state.setBreakingsCause(th);
708
                }
709
            }
710
        } catch(Throwable th) {
711
            state.setBreakingsCause(th);
712
        }
713

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

    
745
                    }
746

    
747
            }
748
        } catch(Throwable th) {
749
            state.setBreakingsCause(th);
750
        }
751

    
752

    
753
        try {
754
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
755
            FeatureType ftype;
756

    
757
            if (defaultFeatureType == null ||
758
                    defaultFeatureType.getId() == null ||
759
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
760

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

    
780
        LOGGER.info("load() broken:{}, {}, {}.",
781
                new Object[] { state.isBroken(), this.getProviderName(), params }
782
        );
783
    }
784

    
785
    public DataStoreProviderServices getStoreProviderServices() {
786
        return this;
787
    }
788

    
789
    public static void registerPersistenceDefinition() {
790
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
791
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
792
            DynStruct definition =
793
                manager.addDefinition(DefaultFeatureStore.class,
794
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
795
                        + " Persistent definition", null, null);
796
            definition.addDynFieldString("dataStoreName").setMandatory(true)
797
                .setPersistent(true);
798

    
799
            definition.addDynFieldObject("parameters")
800
                .setClassOfValue(DynObject.class).setMandatory(true)
801
                .setPersistent(true);
802

    
803
            definition.addDynFieldObject("selection")
804
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
805
                .setPersistent(true);
806

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

    
811
            definition.addDynFieldMap("evaluatedAttributes")
812
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
813
                .setMandatory(false).setPersistent(true);
814

    
815
            definition.addDynFieldString("defaultFeatureTypeId")
816
                .setMandatory(true).setPersistent(true);
817
        }
818
    }
819

    
820
    public static void registerMetadataDefinition() throws MetadataException {
821
        MetadataManager manager = MetadataLocator.getMetadataManager();
822
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
823
            DynStruct metadataDefinition =
824
                manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
825
            metadataDefinition.extend(manager
826
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
827
        }
828
    }
829

    
830
    //
831
    // ====================================================================
832
    // Gestion de la seleccion
833
    //
834

    
835
    @Override
836
    public void setSelection(DataSet selection) throws DataException {
837
        this.setSelection((FeatureSet) selection);
838
    }
839

    
840
    @Override
841
    public DataSet createSelection() throws DataException {
842
        return createFeatureSelection();
843
    }
844

    
845
    @Override
846
    public DataSet getSelection() throws DataException {
847
        return this.getFeatureSelection();
848
    }
849

    
850
    @Override
851
    public void setSelection(FeatureSet selection) throws DataException {
852
        setSelection(selection, true);
853
    }
854

    
855
    public void setSelection(FeatureSet selection, boolean undoable)
856
        throws DataException {
857
        if (selection == null) {
858
            if (undoable) {
859
                throw new SelectionNotAllowedException(getName());
860
            }
861

    
862
        } else {
863
            if (selection.equals(this.selection)) {
864
                return;
865
            }
866
            if (!selection.isFromStore(this)) {
867
                throw new SelectionNotAllowedException(getName());
868
            }
869
        }
870

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

    
909
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
910
    }
911

    
912
    @Override
913
    public FeatureSelection createFeatureSelection() throws DataException {
914
        long maxSize = dataManager.getMaxSizeForSmallFeatureSelection();
915
        if(this.provider.getFeatureCount()>maxSize) {
916
            return createLargeFeatureSelection();
917
        }
918
        return this.provider.createFeatureSelection();
919
    }
920
    
921
    @Override
922
    public FeatureSelection createLargeFeatureSelection() throws DataException {
923
        return new LargeFeatureSelection(this);
924
        
925
    }
926
            
927
    @Override
928
    public FeatureSelection createMemoryFeatureSelection() throws DataException {
929
        return this.provider.createFeatureSelection();
930
    }
931

    
932
    @Override
933
    public FeatureSelection getFeatureSelection() throws DataException {
934
        if (selection == null) {
935
            this.selection = createFeatureSelection();
936
            this.selection.addObserver(this);
937
        }
938
        return selection;
939
    }
940

    
941
    //
942
    // ====================================================================
943
    // Gestion de notificaciones
944
    //
945

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

    
958
    @Override
959
    public FeatureStoreNotification notifyChange(String notification) {
960
      return notifyChange(new DefaultFeatureStoreNotification(this, notification));
961
    }
962
    
963
    public FeatureStoreNotification notifyChange(String notification,
964
      Iterator<FeatureReference> deleteds, 
965
      Iterator<Feature> inserteds, 
966
      Iterator<Feature> updateds, 
967
      Iterator<FeatureTypeChanged> featureTypesChanged, 
968
      boolean isSelectionCompromised) {
969
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
970
            deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised));
971
    }
972

    
973
    @Override
974
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
975
        Feature f = null;
976
        if( data !=null ) {
977
          try {
978
              f = createFeature(data);
979
          } catch (Throwable ex) {
980
              LOGGER.warn("Problems creating a feature to notifying changes in the store '"+this.getName()+" ("+notification+").",ex);
981
          }
982
        }
983
        return notifyChange(notification, f);
984
    }
985

    
986
    public FeatureStoreNotification notifyChange(String notification, Feature feature) {
987
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
988
            feature));
989
    }
990

    
991
    public FeatureStoreNotification notifyChange(String notification, Command command) {
992
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
993
            command));
994
    }
995

    
996
    public FeatureStoreNotification notifyChange(String notification, EditableFeatureType type) {
997
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
998
            type));
999
    }
1000

    
1001
    @Override
1002
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
1003
        return notifyChange(new DefaultFeatureStoreNotification(this,
1004
            DataStoreNotification.RESOURCE_CHANGED));
1005
    }
1006

    
1007
    //
1008
    // ====================================================================
1009
    // Gestion de bloqueos
1010
    //
1011

    
1012
    @Override
1013
    public boolean isLocksSupported() {
1014
        return this.provider.isLocksSupported();
1015
    }
1016

    
1017
    @Override
1018
    public FeatureLocks getLocks() throws DataException {
1019
        if (!this.provider.isLocksSupported()) {
1020
            LOGGER.warn("Locks not supported");
1021
            return null;
1022
        }
1023
        if (locks == null) {
1024
            this.locks = this.provider.createFeatureLocks();
1025
        }
1026
        return locks;
1027
    }
1028

    
1029
    //
1030
    // ====================================================================
1031
    // Interface Observable
1032
    //
1033

    
1034
    @Override
1035
    public void disableNotifications() {
1036
        this.delegateObservable.disableNotifications();
1037

    
1038
    }
1039

    
1040
    @Override
1041
    public void enableNotifications() {
1042
        this.delegateObservable.enableNotifications();
1043
    }
1044

    
1045
    @Override
1046
    public void beginComplexNotification() {
1047
        this.delegateObservable.beginComplexNotification();
1048

    
1049
    }
1050

    
1051
    @Override
1052
    public void endComplexNotification() {
1053
        this.delegateObservable.endComplexNotification();
1054

    
1055
    }
1056

    
1057
    @Override
1058
    public void addObserver(Observer observer) {
1059
        if (delegateObservable != null) {
1060
            this.delegateObservable.addObserver(observer);
1061
        }
1062
    }
1063

    
1064
    @Override
1065
    public void deleteObserver(Observer observer) {
1066
        if (delegateObservable != null) {
1067
            this.delegateObservable.deleteObserver(observer);
1068
        }
1069
    }
1070

    
1071
    @Override
1072
    public void deleteObservers() {
1073
        this.delegateObservable.deleteObservers();
1074

    
1075
    }
1076

    
1077
    //
1078
    // ====================================================================
1079
    // Interface Observer
1080
    //
1081
    // Usado para observar:
1082
    // - su seleccion
1083
    // - sus bloqueos
1084
    // - sus recursos
1085
    //
1086

    
1087
    @Override
1088
    public void update(Observable observable, Object notification) {
1089
        if (observable instanceof FeatureSet) {
1090
            if (observable == this.selection) {
1091
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1092
            } else if (observable == this.locks) {
1093
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1094
            }
1095

    
1096
        } else if (observable instanceof FeatureStoreProvider) {
1097
            if (observable == this.provider) {
1098

    
1099
            }
1100
        } else if (observable instanceof FeatureReferenceSelection) {
1101
            if(notification instanceof String){
1102
                    this.notifyChange((String)notification);
1103
            }
1104
        }
1105
    }
1106

    
1107
    //
1108
    // ====================================================================
1109
    // Edicion
1110
    //
1111

    
1112
    private void newVersionOfUpdate() {
1113
        this.versionOfUpdate++;
1114
    }
1115

    
1116
    private long currentVersionOfUpdate() {
1117
        return this.versionOfUpdate;
1118
    }
1119

    
1120
    private void checkInEditingMode() throws NeedEditingModeException {
1121
        if (mode != MODE_FULLEDIT) {
1122
            throw new NeedEditingModeException(this.getName());
1123
        }
1124
    }
1125

    
1126
    private void checkNotInAppendMode() throws IllegalStateException {
1127
        if (mode == MODE_APPEND) {
1128
                        throw new IllegalStateException("Error: store "
1129
                                        + this.getFullName() + " is in append mode");
1130
        }
1131
    }
1132

    
1133
    private void checkIsOwnFeature(Feature feature)
1134
        throws IllegalFeatureException {
1135
        if (((DefaultFeature) feature).getStore() != this) {
1136
            throw new IllegalFeatureException(this.getName());
1137
        }
1138
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1139
        // fixFeatureType((DefaultFeatureType) feature.getType());
1140
    }
1141

    
1142
    private void exitEditingMode() {
1143
        if (commands != null) {
1144
            commands.clear();
1145
            commands = null;
1146
        }
1147

    
1148
        if (featureTypeManager != null) {
1149
            featureTypeManager.dispose();
1150
            featureTypeManager = null;
1151

    
1152
        }
1153

    
1154
        // TODO implementar un dispose para estos dos
1155
        featureManager = null;
1156
        spatialManager = null;
1157

    
1158
        featureCount = null;
1159

    
1160
        mode = MODE_QUERY;
1161
        hasStrongChanges = true; // Lo deja a true por si las moscas
1162
        hasInserts = true;
1163
    }
1164

    
1165
    @Override
1166
    synchronized public void edit() throws DataException {
1167
        edit(MODE_FULLEDIT);
1168
    }
1169

    
1170
    @Override
1171
    synchronized public void edit(int mode) throws DataException {
1172
        LOGGER.debug("Starting editing in mode: {}", mode);
1173
        try {
1174
            if (this.mode != MODE_QUERY) {
1175
                throw new AlreadyEditingException(this.getName());
1176
            }
1177
            if (!this.provider.supportsAppendMode()) {
1178
                mode = MODE_FULLEDIT;
1179
            }
1180
            switch (mode) {
1181
            case MODE_QUERY:
1182
                throw new IllegalStateException(this.getName());
1183

    
1184
            case MODE_FULLEDIT:
1185
                if (!this.transforms.isEmpty()) {
1186
                    throw new IllegalStateException(this.getName());
1187
                }
1188
                if( notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING).isCanceled() ) {
1189
                  return;
1190
                }
1191
                invalidateIndexes();
1192
                featureManager = new FeatureManager();
1193
                featureTypeManager = new FeatureTypeManager(this);
1194
                spatialManager = new SpatialManager(this, provider.getEnvelope());
1195

    
1196
                commands = new DefaultFeatureCommandsStack(
1197
                        this, featureManager,
1198
                        spatialManager, featureTypeManager);
1199
                this.mode = MODE_FULLEDIT;
1200
                hasStrongChanges = false;
1201
                hasInserts = false;
1202
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1203
                break;
1204
            case MODE_APPEND:
1205
                if (!this.transforms.isEmpty()) {
1206
                    throw new IllegalStateException(this.getName());
1207
                }
1208
                if( notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING).isCanceled() ) {
1209
                  return;
1210
                }
1211
                invalidateIndexes();
1212
                this.provider.beginAppend();
1213
                this.mode = MODE_APPEND;
1214
                hasInserts = false;
1215
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1216
                break;
1217
            case MODE_PASS_THROUGH:
1218
                if(!this.provider.supportsPassThroughMode()){
1219
                    throw new IllegalStateException(this.getName());
1220
                }
1221
                if (!this.transforms.isEmpty()) {
1222
                    throw new IllegalStateException(this.getName());
1223
                }
1224
                if( notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING).isCanceled() ) {
1225
                  return;
1226
                }
1227
                invalidateIndexes();
1228
                this.mode = MODE_PASS_THROUGH;
1229
                hasInserts = false;
1230
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1231
                break;
1232
                
1233
                
1234
            }
1235
        } catch (Exception e) {
1236
            throw new StoreEditException(e, this.getName());
1237
        }
1238
    }
1239

    
1240
    private void invalidateIndexes() {
1241
        setIndexesValidStatus(false);
1242
    }
1243

    
1244
    private void setIndexesValidStatus(boolean valid) {
1245
        FeatureIndexes theIndexes = getIndexes();
1246
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1247
            ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1248
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1249
            FeatureIndex index = (FeatureIndex) iterator.next();
1250
            if (index instanceof FeatureIndexProviderServices) {
1251
                FeatureIndexProviderServices indexServices =
1252
                    (FeatureIndexProviderServices) index;
1253
                indexServices.setValid(valid);
1254
            }
1255
        }
1256
    }
1257

    
1258
    private void updateIndexes() throws FeatureIndexException {
1259
        FeatureIndexes theIndexes = getIndexes();
1260
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1261
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1262
            FeatureIndex index = (FeatureIndex) iterator.next();
1263
            if (index instanceof FeatureIndexProviderServices) {
1264
                FeatureIndexProviderServices indexServices =
1265
                    (FeatureIndexProviderServices) index;
1266
                indexServices.fill(true, null);
1267
            }
1268
        }
1269
    }
1270

    
1271
    private void waitForIndexes() {
1272
        FeatureIndexes theIndexes = getIndexes();
1273
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1274
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1275
            FeatureIndex index = (FeatureIndex) iterator.next();
1276
            if (index instanceof FeatureIndexProviderServices) {
1277
                FeatureIndexProviderServices indexServices =
1278
                    (FeatureIndexProviderServices) index;
1279
                indexServices.waitForIndex();
1280
            }
1281
        }
1282
    }
1283

    
1284
    private void disposeIndexes() {
1285
        FeatureIndexes theIndexes = getIndexes();
1286
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1287
        if( theIndexes==null ) {
1288
            return;
1289
        }
1290
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1291
            FeatureIndex index = (FeatureIndex) iterator.next();
1292
            if (index instanceof FeatureIndexProviderServices) {
1293
                FeatureIndexProviderServices indexServices =
1294
                    (FeatureIndexProviderServices) index;
1295
                indexServices.dispose();
1296
            }
1297
        }
1298
    }
1299

    
1300
    @Override
1301
    public boolean isEditing() {
1302
        return mode == MODE_FULLEDIT;
1303
    }
1304

    
1305
    @Override
1306
    public boolean isAppending() {
1307
        return mode == MODE_APPEND;
1308
    }
1309

    
1310
    @Override
1311
    synchronized public void update(EditableFeatureType type)
1312
        throws DataException {
1313
        try {
1314
            if (type == null) {
1315
                throw new NullFeatureTypeException(getName());
1316
            }
1317
            
1318
            switch(this.mode) {
1319
                case MODE_QUERY:
1320
                    if (type.hasOnlyMetadataChanges(this.defaultFeatureType)) {
1321
                        if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled() ) {
1322
                          return;
1323
                        }
1324
                        FeatureType theType = type.getNotEditableCopy();
1325
                        if( defaultFeatureType.getId().equals(theType.getId()) ) {
1326
                            defaultFeatureType = theType;
1327
                        }
1328
                        List newtypes = new ArrayList();
1329
                        for (FeatureType featureType : this.featureTypes) {
1330
                            if( featureType.getId().equals(theType.getId()) ) {
1331
                                newtypes.add(theType);
1332
                            } else {
1333
                                newtypes.add(featureType);
1334
                            }                    
1335
                        }
1336
                        this.featureTypes = newtypes;
1337
                        saveDALFile();
1338
                        notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1339
                    }
1340
                    
1341
                    break;
1342
                case MODE_FULLEDIT:
1343
                    if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled() ) {
1344
                      return;
1345
                    }
1346
                    newVersionOfUpdate();
1347

    
1348
                    FeatureType oldt = type.getSource().getCopy();
1349
                    FeatureType newt = type.getCopy();
1350
                    commands.update(newt, oldt);
1351
                    hasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1352
                    notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);                    
1353
                    break;
1354
                case MODE_APPEND:
1355
                case MODE_PASS_THROUGH:
1356
                    throw new NeedEditingModeException(this.getName());
1357
                    
1358
            }
1359
        } catch (Exception e) {
1360
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1361
        }
1362
    }
1363

    
1364
    @Override
1365
    public void delete(Feature feature) throws DataException {
1366
        switch (this.mode){
1367
            case MODE_PASS_THROUGH:
1368
                this.provider.passThroughDelete((FeatureReferenceProviderServices) feature.getReference());
1369
                break;
1370
            default:
1371
                this.commands.delete(feature);
1372
                break;
1373
                
1374
        }
1375
    }
1376
    
1377
    @Override
1378
    public void delete(String filter) {
1379
        if( StringUtils.isBlank(filter) ) {
1380
            return;
1381
        }
1382
        this.delete(ExpressionUtils.createExpression(filter));
1383
    }
1384
    
1385
    @Override
1386
    public void delete(Expression filter) {
1387
        // TODO: Optimizar pasandolo directamente al proveedor si no estamos en edicion y lo soporta.
1388
        if( filter == null ) {
1389
            return;
1390
        }
1391
        boolean pendingFinishEditing = false;
1392
        DisposableFeatureSetIterable features = null;
1393
        try {
1394
            switch(this.mode) {
1395
                case MODE_QUERY:
1396
                    pendingFinishEditing = true;
1397
                    this.edit();
1398
                    break;
1399
                case MODE_APPEND:
1400
                    throw new IllegalStateException("Delete not allowed in append mode.");
1401
                case MODE_FULLEDIT:
1402
                    break;
1403
                case MODE_PASS_THROUGH:
1404
//                    this.provider.passThroughDelete(filter);
1405
//                    return;
1406
                    break;
1407
                default:
1408
                    throw new IllegalStateException("Mode "+this.mode+" not supported.");
1409
            }
1410
            
1411
            FeatureSet fset = this.getFeatureSet(filter);
1412
            features = fset.iterable(); 
1413
            for (Feature f : features) {
1414
                fset.delete(f);
1415
            }
1416
        } catch(DataException ex) {
1417
            throw new DataRuntimeException(ex.getFormatString(), ex.getMessageKey(), ex.getCode()) {};
1418
        } catch(Exception ex) {
1419
            throw new RuntimeException("Can't delete features ("+filter.getPhrase()+").", ex);
1420
        } finally {
1421
            if( pendingFinishEditing ) {
1422
                this.finishEditingQuietly();
1423
            }
1424
            DisposeUtils.disposeQuietly(features);
1425
        }
1426
    }
1427
    
1428
    synchronized public void doDelete(Feature feature) throws DataException {
1429
        if( feature==null ) {
1430
            throw new IllegalArgumentException("feature argument can't be null.");
1431
        }
1432
        try {
1433
            checkInEditingMode();
1434
            checkIsOwnFeature(feature);
1435
            if (feature instanceof EditableFeature) {
1436
                throw new StoreDeleteEditableFeatureException(getName());
1437
            }
1438
            if( notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled() ) {
1439
              return;
1440
            }
1441

    
1442
            //Update the featureManager and the spatialManager
1443
            featureManager.delete(feature);
1444
            spatialManager.deleteFeature(feature);
1445

    
1446
            newVersionOfUpdate();
1447
            hasStrongChanges = true;
1448
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1449
        } catch (Exception e) {
1450
            throw new StoreDeleteFeatureException(e, this.getName());
1451
        }
1452
    }
1453

    
1454
    @Override
1455
    public synchronized void insert(FeatureSet set) throws DataException {
1456
        switch (mode) {
1457
        case MODE_QUERY:
1458
            throw new NeedEditingModeException(this.getName());
1459

    
1460
        case MODE_APPEND:
1461
        case MODE_FULLEDIT:
1462
        case MODE_PASS_THROUGH:
1463
            try {
1464
                set.accept((Object obj) -> {
1465
                    EditableFeature ef = createNewFeature((Feature) obj);
1466
                    insert(ef);
1467
                });
1468
            } catch (BaseException ex) {
1469
                throw new StoreInsertFeatureException(ex, this.getName());
1470
            }
1471
            break;
1472
        }
1473
    }
1474
    
1475
    private static EditableFeature lastChangedFeature = null;
1476

    
1477
    @Override
1478
    public synchronized void insert(EditableFeature feature)
1479
        throws DataException {
1480
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1481
        try {
1482
            switch (mode) {
1483
            case MODE_QUERY:
1484
                throw new NeedEditingModeException(this.getName());
1485

    
1486
            case MODE_APPEND:
1487
                checkIsOwnFeature(feature);
1488
                if (feature.getSource() != null) {
1489
                    throw new NoNewFeatureInsertException(this.getName());
1490
                }
1491
                if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1492
                  return;
1493
                }
1494
                this.featureCount = null;
1495
                feature.validate(Feature.UPDATE);
1496
                provider.append(((DefaultEditableFeature) feature).getData());
1497
                hasStrongChanges = true;
1498
                hasInserts = true;
1499
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1500
                break;
1501

    
1502
            case MODE_FULLEDIT:
1503
                if (feature.getSource() != null) {
1504
                    throw new NoNewFeatureInsertException(this.getName());
1505
                }
1506
                feature.validate(Feature.UPDATE);
1507
                commands.insert(feature);
1508
                break;
1509
                
1510
            case MODE_PASS_THROUGH:
1511
                this.provider.passThroughInsert(((DefaultEditableFeature) feature).getData());
1512
                break;
1513
            }
1514
        } catch (Exception e) {
1515
            throw new StoreInsertFeatureException(e, this.getName());
1516
        }
1517
    }
1518

    
1519
    synchronized public void doInsert(EditableFeature feature)
1520
        throws DataException {
1521
        checkIsOwnFeature(feature);
1522

    
1523
        waitForIndexes();
1524

    
1525
        if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1526
          return;
1527
        }
1528
        newVersionOfUpdate();
1529
        if ((lastChangedFeature == null)
1530
            || (lastChangedFeature.getSource() != feature.getSource())) {
1531
            lastChangedFeature = feature;
1532
            feature.validate(Feature.UPDATE);
1533
            lastChangedFeature = null;
1534
        }
1535
        //Update the featureManager and the spatialManager
1536
        ((DefaultEditableFeature) feature).setInserted(true);
1537
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1538

    
1539

    
1540
        featureManager.add(newFeature);
1541
        spatialManager.insertFeature(newFeature);
1542

    
1543
        hasStrongChanges = true;
1544
        hasInserts = true;
1545
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1546
    }
1547

    
1548
    @Override
1549
    public void update(EditableFeature feature)
1550
    throws DataException {
1551
        switch (this.mode){
1552
        case MODE_PASS_THROUGH:
1553
            this.provider.passThroughUpdate(((DefaultEditableFeature)feature).getData());
1554
            break;
1555
        case MODE_FULLEDIT:
1556
            if (feature.isUpdatable()) {
1557
                commands.update(feature, feature.getSource());
1558
                return;
1559
            }
1560
            // FIXME: Deberiamos lanzar aqui un error en lugar de hacer el insert.
1561
            //        �O lanzar un mensaje al log?
1562
            insert(feature);
1563
            break;
1564
        default:
1565
            throw new NeedEditingModeException(this.getName());
1566
        }
1567
    }
1568

    
1569
    @Override
1570
    public void update(Object... parameters) throws DataException {
1571
        if(parameters.length == 1){
1572
            this.update((EditableFeature)parameters[0]);
1573
            return;
1574
        }
1575
        
1576
        Expression filter = null;
1577
        long end = parameters.length;
1578
        if(parameters.length % 2 == 1){
1579
            Object param = parameters[parameters.length-1];
1580
            if(param != null){
1581
                if(param instanceof Expression){
1582
                    filter = (Expression) param;
1583
                } else {
1584
                    filter = ExpressionUtils.createExpression(param.toString());
1585
                }
1586
            }
1587
        } else {
1588
            end = parameters.length-1;
1589
        }
1590
        
1591
        switch (this.mode){
1592
        case MODE_PASS_THROUGH:
1593
            this.provider.passThroughUpdate(
1594
//                    this.getName(), 
1595
                    parameters, 
1596
                    filter);
1597
            break;
1598
        case MODE_FULLEDIT:
1599
            FeatureSet set = this.getFeatureSet(filter);
1600
            DisposableIterator it = set.fastIterator();
1601
            while (it.hasNext()) {
1602
                Feature feature = (Feature) it.next();
1603
                EditableFeature ef = feature.getEditable();
1604
                for (int i = 0; i < end; i+=2) {
1605
                    String name = (String) parameters[i];
1606
                    Object value = parameters[i+1];
1607
                    ef.set(name, value);
1608
                }
1609
                set.update(ef);
1610
            }
1611
            DisposeUtils.disposeQuietly(it);
1612
            DisposeUtils.disposeQuietly(set);
1613
            break;
1614
        default:
1615
            throw new NeedEditingModeException(this.getName());
1616
        }
1617
    }
1618

    
1619
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1620
        throws DataException {
1621
        try {
1622
            checkInEditingMode();
1623
            checkIsOwnFeature(feature);
1624
            if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled() ) {
1625
              return;
1626
            }
1627
            newVersionOfUpdate();
1628
            if ((lastChangedFeature == null)
1629
                || (lastChangedFeature.getSource() != feature.getSource())) {
1630
                lastChangedFeature = feature;
1631
                feature.validate(Feature.UPDATE);
1632
                lastChangedFeature = null;
1633
            }
1634

    
1635
            //Update the featureManager and the spatialManager
1636
            Feature newf = feature.getNotEditableCopy();
1637
            featureManager.update(newf, oldFeature);
1638
            spatialManager.updateFeature(newf, oldFeature);
1639

    
1640
            hasStrongChanges = true;
1641
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1642
        } catch (Exception e) {
1643
            throw new StoreUpdateFeatureException(e, this.getName());
1644
        }
1645
    }
1646

    
1647
    @Override
1648
    synchronized public void redo() throws RedoException {
1649
        Command redo = commands.getNextRedoCommand();
1650
        try {
1651
            checkInEditingMode();
1652
        } catch (NeedEditingModeException ex) {
1653
            throw new RedoException(redo, ex);
1654
        }
1655
        if( notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled() ) {
1656
          return;
1657
        }
1658
        newVersionOfUpdate();
1659
        commands.redo();
1660
        hasStrongChanges = true;
1661
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1662
    }
1663

    
1664
    @Override
1665
    synchronized public void undo() throws UndoException {
1666
        Command undo = commands.getNextUndoCommand();
1667
        try {
1668
            checkInEditingMode();
1669
        } catch (NeedEditingModeException ex) {
1670
            throw new UndoException(undo, ex);
1671
        }
1672
        if( notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled() ) {
1673
          return;
1674
        }
1675
        newVersionOfUpdate();
1676
        commands.undo();
1677
        hasStrongChanges = true;
1678
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1679
    }
1680

    
1681
    @Override
1682
    public List getRedoInfos() {
1683
        if (isEditing() && (commands != null)) {
1684
            return commands.getRedoInfos();
1685
        } else {
1686
            return null;
1687
        }
1688
    }
1689

    
1690
    @Override
1691
    public List getUndoInfos() {
1692
        if (isEditing() && (commands != null)) {
1693
            return commands.getUndoInfos();
1694
        } else {
1695
            return null;
1696
        }
1697
    }
1698

    
1699
    public synchronized FeatureCommandsStack getCommandsStack()
1700
        throws DataException {
1701
        checkInEditingMode();
1702
        return commands;
1703
    }
1704

    
1705
    @Override
1706
    public boolean cancelEditingQuietly() {
1707
        try {
1708
            this.cancelEditing();
1709
            return true;
1710
        } catch(Exception ex) {
1711
            LOGGER.debug("Can't cancel editing", ex);
1712
            return false;
1713
        }
1714
    }
1715
    
1716
    @Override
1717
    synchronized public void cancelEditing() throws DataException {
1718
        if( spatialManager!=null ) {
1719
            spatialManager.cancelModifies();
1720
        }
1721
        try {
1722
            switch (mode) {
1723
            case MODE_QUERY:
1724
                throw new NeedEditingModeException(this.getName());
1725

    
1726
            case MODE_APPEND:
1727
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1728
                  return;
1729
                }
1730
                provider.abortAppend();
1731
                exitEditingMode();
1732
                ((FeatureSelection) this.getSelection()).deselectAll();
1733
                updateIndexes();
1734
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1735
                break;
1736

    
1737
            case MODE_FULLEDIT:
1738
                boolean clearSelection = this.hasStrongChanges;
1739
                if (this.selection instanceof FeatureReferenceSelection) {
1740
                    clearSelection = this.hasInserts;
1741
                }
1742
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1743
                  return;
1744
                }
1745
                exitEditingMode();
1746
                if (clearSelection) {
1747
                    ((FeatureSelection) this.getSelection()).deselectAll();
1748
                }
1749
                updateIndexes();
1750
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);  
1751
                break;
1752

    
1753
            case MODE_PASS_THROUGH:
1754
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1755
                  return;
1756
                }
1757
                exitEditingMode();
1758
                ((FeatureSelection) this.getSelection()).deselectAll();
1759
                updateIndexes();
1760
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);  
1761
                break;
1762
            }
1763
        } catch (Exception e) {
1764
            throw new StoreCancelEditingException(e, this.getName());
1765
        }
1766
    }
1767

    
1768
    @Override
1769
    public boolean finishEditingQuietly() {
1770
        try {
1771
            this.finishEditing();
1772
            return true;
1773
        } catch(Exception ex) {
1774
            LOGGER.debug("Can't finish editing", ex);
1775
            return false;
1776
        }
1777
    }
1778
    
1779
    @Override
1780
    synchronized public void finishEditing() throws DataException {
1781
        LOGGER.debug("finish editing of mode: {}", mode);
1782
        try {
1783

    
1784
            /*
1785
             * Selection needs to be cleared when editing stops
1786
             * to prevent conflicts with selection remaining from
1787
             * editing mode.
1788
             */
1789
//            ((FeatureSelection) this.getSelection()).deselectAll();
1790
            Map<String,List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1791
            switch (mode) {
1792
            case MODE_QUERY:
1793
                throw new NeedEditingModeException(this.getName());
1794

    
1795
            case MODE_APPEND:
1796
                if( selection!=null ) {
1797
                    selection = null;
1798
                }
1799
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled() ) {
1800
                  return;
1801
                }
1802
                saveDALFile();
1803
                provider.endAppend();
1804
                exitEditingMode();
1805
                this.updateComputedFields(computedFields);
1806
                loadDALFile();
1807
                updateIndexes();
1808
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1809
                break;
1810

    
1811
            case MODE_FULLEDIT:
1812
                if( featureManager.hasChanges() || featureTypeManager.hasChanges() )  {
1813
                    if (hasStrongChanges && !this.allowWrite()) {
1814
                        throw new WriteNotAllowedException(getName());
1815
                    }
1816
                    if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, 
1817
                            featureManager.getDeleted(),
1818
                            featureManager.getInsertedFeatures(),
1819
                            featureManager.getUpdatedFeatures(),
1820
                            featureTypeManager.getFeatureTypesChanged().iterator(),
1821
                            featureManager.isSelectionCompromised()).isCanceled() ) {
1822
                      return;
1823
                    }
1824
                    saveDALFile();
1825
                    if(featureManager.isSelectionCompromised() && selection!=null ) {
1826
                        selection = null;
1827
                    }
1828
                    if (hasStrongChanges) {
1829
                        validateFeatures(Feature.FINISH_EDITING);
1830

    
1831
                        /*
1832
                         * This will throw a PerformEditingExceptionif the provider
1833
                         * does not accept the changes (for example, an invalid field name)
1834
                         */
1835
                        provider.performChanges(featureManager.getDeleted(),
1836
                            featureManager.getInserted(),
1837
                            featureManager.getUpdated(),
1838
                            removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1839

    
1840
                    }  
1841
                    this.updateComputedFields(computedFields);
1842
                    exitEditingMode();
1843
                    loadDALFile();
1844
                    updateIndexes();
1845
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1846
                } else {
1847
                    exitEditingMode();
1848
                }
1849
                break;
1850
            case MODE_PASS_THROUGH:
1851
                if( selection!=null ) {
1852
                    selection = null;
1853
                }
1854
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled() ) {
1855
                  return;
1856
                }
1857
                exitEditingMode();
1858
                updateIndexes();
1859
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1860
                break;
1861
            }
1862
        } catch (PerformEditingException pee) {
1863
            throw new WriteException(provider.getSourceId().toString(), pee);
1864
        } catch (Exception e) {
1865
            throw new FinishEditingException(e);
1866
        }
1867
    }
1868
    private Map<String,List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
1869
        Map<String,List<FeatureAttributeDescriptor>> r = new HashMap<>();
1870
        
1871
        List<FeatureType> theTypes = new ArrayList<>();
1872
        theTypes.addAll(this.getFeatureTypes());
1873
        theTypes.add(this.getDefaultFeatureType());
1874
        for( int n=0; n<theTypes.size(); n++ ) {
1875
            FeatureType type = theTypes.get(n);
1876
                for (FeatureAttributeDescriptor attrdesc : type) {
1877
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
1878
                    if( emulator!= null) {
1879
                        List<FeatureAttributeDescriptor> l = r.get(type.getId());
1880
                        if (l==null) {
1881
                            l = new ArrayList<>();
1882
                            r.put(type.getId(), l);
1883
                        }
1884
                        l.add(attrdesc);
1885
                    }
1886
            }
1887
        }
1888
        return r;
1889
    }
1890
    private void updateComputedFields(Map<String,List<FeatureAttributeDescriptor>> computedFields) throws DataException {
1891

    
1892
        List<FeatureType> theTypes = new ArrayList<>();
1893
        theTypes.addAll(this.getFeatureTypes());
1894
        theTypes.add(this.getDefaultFeatureType());
1895
        for( int n=0; n<theTypes.size(); n++ ) {
1896
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1897
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1898
            if(x!=null && !x.isEmpty()) {
1899
                for (FeatureAttributeDescriptor attrdesc : x) {
1900
                    if (type.get(attrdesc.getName())==null) {
1901
                        type.add(attrdesc);
1902
                    }
1903
                }
1904
            }
1905
        }
1906
        
1907
    }
1908
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
1909
        // FIXME: Falta por implementar
1910
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
1911
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
1912
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
1913
//                if (attributeDescriptor.isComputed()) {
1914
//                    target.remove(attributeDescriptor.getName());
1915
//                }
1916
//            }
1917
//        }
1918
        return ftypes;
1919
    }
1920
    
1921

    
1922
    private void saveDALFile() {       
1923
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1924
        try {
1925
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1926
            if( resourcesStorage == null || resourcesStorage.isReadOnly() ) {
1927
                return;
1928
            }
1929
            resource = resourcesStorage.getResource("dal");
1930
            if( resource == null || resource.isReadOnly() ) {
1931
                return;
1932
            }
1933
            DALFile dalFile = DALFile.getDALFile();
1934
            dalFile.setStore(this);
1935
            if( !dalFile.isEmpty() ) {
1936
                dalFile.write(resource);
1937
            }
1938
        } catch (Throwable ex) {
1939
            LOGGER.warn("Can't save DAL resource", ex);
1940
        } finally {
1941
            IOUtils.closeQuietly(resource);
1942
        }
1943
    }
1944
    
1945
    private void loadDALFile() {
1946
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1947
        try {
1948
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1949
            if( resourcesStorage == null ) {
1950
                return;
1951
            }
1952
            resource = resourcesStorage.getResource("dal");
1953
            if( resource == null || !resource.exists() ) {
1954
                return;
1955
            }
1956
            DALFile dalFile = DALFile.getDALFile(resource);
1957
            if( !dalFile.isEmpty() ) {
1958
                dalFile.updateStore(this);
1959
            }
1960
        } catch (Throwable ex) {
1961
            LOGGER.warn("Can't load DAL resource", ex);
1962
        } finally {
1963
            IOUtils.closeQuietly(resource);
1964
        }
1965
    }
1966
    
1967
    /**
1968
     * Save changes in the provider without leaving the edit mode.
1969
     * Do not call observers to communicate a change of ediding mode.
1970
     * The operation's history is eliminated to prevent inconsistencies
1971
     * in the data.
1972
     *
1973
     * @throws DataException
1974
     */
1975
    @Override
1976
    synchronized public void commitChanges() throws DataException {
1977
      LOGGER.debug("commitChanges of mode: {}", mode);
1978
      if( !canCommitChanges() ) {
1979
              throw new WriteNotAllowedException(getName());
1980
      }
1981
      try {
1982
        switch (mode) {
1983
        case MODE_QUERY:
1984
          throw new NeedEditingModeException(this.getName());
1985

    
1986
        case MODE_APPEND:
1987
          this.provider.endAppend();
1988
          exitEditingMode();
1989
          invalidateIndexes();
1990
          this.provider.beginAppend();
1991
          hasInserts = false;
1992
          break;
1993

    
1994
        case MODE_FULLEDIT:
1995
          if (hasStrongChanges && !this.allowWrite()) {
1996
            throw new WriteNotAllowedException(getName());
1997
          }
1998
          if (hasStrongChanges) {
1999
            validateFeatures(Feature.FINISH_EDITING);
2000
            provider.performChanges(featureManager.getDeleted(),
2001
              featureManager.getInserted(),
2002
              featureManager.getUpdated(),
2003
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2004
          }
2005
          invalidateIndexes();
2006
          featureManager = new FeatureManager();
2007
          featureTypeManager = new FeatureTypeManager(this);
2008
          spatialManager = new SpatialManager(this, provider.getEnvelope());
2009

    
2010
          commands =
2011
            new DefaultFeatureCommandsStack(this, featureManager,
2012
              spatialManager, featureTypeManager);
2013
          featureCount = null;
2014
          hasStrongChanges = false;
2015
          hasInserts = false;
2016
          break;
2017
        }
2018
      } catch (Exception e) {
2019
        throw new FinishEditingException(e);
2020
      }
2021
    }
2022

    
2023
    @Override
2024
    synchronized public boolean canCommitChanges() throws DataException {
2025
        if ( !this.allowWrite()) {
2026
                return false;
2027
        }
2028
            switch (mode) {
2029
            default:
2030
        case MODE_QUERY:
2031
                return false;
2032

    
2033
        case MODE_APPEND:
2034
                return true;
2035

    
2036
        case MODE_FULLEDIT:
2037
            List types = this.getFeatureTypes();
2038
            for( int i=0; i<types.size(); i++ ) {
2039
                    Object type = types.get(i);
2040
                    if( type instanceof DefaultEditableFeatureType ) {
2041
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
2042
                                    return false;
2043
                            }
2044
                    }
2045
            }
2046
            return true;
2047
            }
2048
    }
2049

    
2050
    @Override
2051
    public void beginEditingGroup(String description)
2052
        throws NeedEditingModeException {
2053
        checkInEditingMode();
2054
        commands.startComplex(description);
2055
    }
2056

    
2057
    @Override
2058
    public void endEditingGroup() throws NeedEditingModeException {
2059
        checkInEditingMode();
2060
        commands.endComplex();
2061
    }
2062

    
2063
    @Override
2064
    public boolean isAppendModeSupported() {
2065
        return this.provider.supportsAppendMode();
2066
    }
2067

    
2068
    @Override
2069
    public void export(DataServerExplorer explorer, String provider,
2070
        NewFeatureStoreParameters params, String name) throws DataException {
2071

    
2072
        if (this.getFeatureTypes().size() != 1) {
2073
            throw new NotYetImplemented(
2074
                "export whith more than one type not yet implemented");
2075
        }
2076
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2077
        FeatureStore target = null;
2078
        FeatureSet features = null;
2079
        DisposableIterator iterator = null;
2080
        try {
2081
            FeatureType type = this.getDefaultFeatureType();
2082
            if ((params.getDefaultFeatureType() == null)
2083
                || (params.getDefaultFeatureType().size() == 0)) {
2084
                params.setDefaultFeatureType(type.getEditable());
2085

    
2086
            }
2087
            explorer.add(provider, params, true);
2088
            DataManager manager = DALLocator.getDataManager();
2089
            
2090
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2091
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2092

    
2093
            target = (FeatureStore) manager.openStore(provider, openParams);
2094
            FeatureType targetType = target.getDefaultFeatureType();
2095

    
2096
            target.edit(MODE_APPEND);
2097
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2098
            if (featureSelection.getSize() > 0) {
2099
                features = this.getFeatureSelection();
2100
            } else {
2101
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2102
                    FeatureQuery query = createFeatureQuery();
2103
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2104
                        query.getOrder().add(pkattr.getName(), true);
2105
                    }
2106
                    features = this.getFeatureSet(query);
2107
                } else {
2108
                    features = this.getFeatureSet();
2109
                }
2110
            }
2111
            iterator = features.fastIterator();
2112
            while (iterator.hasNext()) {
2113
                DefaultFeature feature = (DefaultFeature) iterator.next();
2114
                target.insert(target.createNewFeature(targetType, feature));
2115
            }
2116
            target.finishEditing();
2117
            target.dispose();
2118
        } catch (Exception e) {
2119
            throw new DataExportException(e, params.toString());
2120
        } finally {
2121
            dispose(iterator);
2122
            dispose(features);
2123
            dispose(target);
2124
        }
2125
    }
2126

    
2127
    @Override
2128
    public void copyTo(final FeatureStore target) {
2129
        boolean finishEditingAtEnd = false;
2130
        try {
2131
            if( !target.isEditing() && !target.isAppending() ) {
2132
                finishEditingAtEnd = true;
2133
                target.edit(MODE_APPEND);
2134
            }
2135
            this.accept((Object obj) -> {
2136
                Feature f_src = (Feature) obj;
2137
                EditableFeature f_dst = target.createNewFeature(f_src);
2138
                target.insert(f_dst);
2139
            });
2140
            if( finishEditingAtEnd ) {
2141
                target.finishEditing();
2142
            }
2143
            
2144
        } catch(Exception ex) {
2145
            try {
2146
                if( finishEditingAtEnd ) {
2147
                    target.cancelEditing();
2148
                }
2149
            } catch (Exception ex1) {
2150
            }
2151
            throw new RuntimeException("Can't copy store.",ex);
2152
        }
2153
            
2154
    }
2155
    
2156
    //
2157
    // ====================================================================
2158
    // Obtencion de datos
2159
    // getDataCollection, getFeatureCollection
2160
    //
2161

    
2162
    @Override
2163
    public DataSet getDataSet() throws DataException {
2164
        checkNotInAppendMode();
2165
        FeatureQuery query =
2166
            new DefaultFeatureQuery(this.getDefaultFeatureType());
2167
        return new DefaultFeatureSet(this, query);
2168
    }
2169

    
2170
    @Override
2171
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2172
        checkNotInAppendMode();
2173
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2174
    }
2175

    
2176
    @Override
2177
    public void getDataSet(Observer observer) throws DataException {
2178
        checkNotInAppendMode();
2179
        this.getFeatureSet(null, observer);
2180
    }
2181

    
2182
    @Override
2183
    public void getDataSet(DataQuery dataQuery, Observer observer)
2184
        throws DataException {
2185
        checkNotInAppendMode();
2186
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2187
    }
2188

    
2189
    @Override
2190
    public FeatureSet getFeatureSet() throws DataException {
2191
        return this.getFeatureSet((FeatureQuery)null);
2192
    }
2193

    
2194
    @Override
2195
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2196
        throws DataException {
2197
        checkNotInAppendMode();
2198
        if( featureQuery==null ) {
2199
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2200
        }
2201
        return new DefaultFeatureSet(this, featureQuery);
2202
    }
2203

    
2204
    @Override
2205
    public FeatureSet getFeatureSet(String filter) throws DataException {
2206
        return this.getFeatureSet(filter, null, true);
2207
    }
2208

    
2209
    @Override
2210
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2211
        return this.getFeatureSet(filter, sortBy, true);
2212
    }
2213

    
2214
    @Override
2215
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2216
        return this.getFeatureSet(filter, null, true);
2217
    }
2218
    
2219
    @Override
2220
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2221
        return this.getFeatureSet(filter, sortBy, true);
2222
    }
2223

    
2224
    @Override
2225
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2226
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2227
        return this.getFeatureSet(query);
2228
    }
2229
    
2230
    @Override
2231
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2232
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2233
        return this.getFeatureSet(query);
2234
    }
2235
    
2236
    @Override
2237
    public List<Feature> getFeatures(String filter)  {
2238
        return this.getFeatures(filter, null, true);
2239
    }
2240

    
2241
    @Override
2242
    public List<Feature> getFeatures(String filter, String sortBy)  {
2243
        return this.getFeatures(filter, sortBy, true);
2244
    }
2245

    
2246
    @Override
2247
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
2248
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2249
        return this.getFeatures(query, 0);
2250
    }
2251
    
2252
    @Override
2253
    public List<Feature> getFeatures(Expression filter)  {
2254
        return this.getFeatures(filter, null, true);
2255
    }
2256

    
2257
    @Override
2258
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
2259
        return this.getFeatures(filter, sortBy, true);
2260
    }
2261

    
2262
    @Override
2263
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
2264
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2265
        return this.getFeatures(query, 0);
2266
    }
2267
    
2268
    @Override
2269
    public List<Feature> getFeatures(FeatureQuery query)  {
2270
        return this.getFeatures(query, 0);
2271
    }
2272
    
2273
    @Override
2274
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
2275
        try {
2276
            if( pageSize<=0 ) {
2277
                pageSize = 100;
2278
            }
2279
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2280
            return pager.asList();
2281
        } catch (BaseException ex) {
2282
            throw new RuntimeException("Can't create the list of features.", ex);
2283
        }
2284
    }
2285

    
2286
    @Override
2287
    public List<Feature> getFeatures() {
2288
        return this.getFeatures(null, 0);
2289
    }
2290

    
2291
    @Override
2292
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2293
        return this.getFeatures64(null, 0);
2294
    }
2295

    
2296
    @Override
2297
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2298
        return this.getFeatures64(filter, null, true);
2299
    }
2300
    
2301
    @Override
2302
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc)  {
2303
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2304
        return this.getFeatures64(query, 0);
2305
    }
2306

    
2307
    @Override
2308
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize)  {
2309
        try {
2310
            if( pageSize<=0 ) {
2311
                pageSize = 100;
2312
            }
2313
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2314
            return pager;
2315
        } catch (BaseException ex) {
2316
            throw new RuntimeException("Can't create the list of features.", ex);
2317
        }
2318
    }
2319

    
2320
    @Override
2321
    public Feature first() throws DataException {
2322
        return this.findFirst((FeatureQuery)null);
2323
    }
2324
    
2325
    @Override
2326
    public Feature findFirst(String filter) throws DataException {
2327
        return this.findFirst(filter, (String)null, true);
2328
    }
2329

    
2330
    @Override
2331
    public Feature findFirst(String filter, String sortBy) throws DataException {
2332
        return this.findFirst(filter, sortBy, true);
2333
    }
2334

    
2335
    @Override
2336
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2337
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2338
        return findFirst(query);
2339
    }
2340

    
2341
    @Override
2342
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2343
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2344
        return findFirst(query);
2345
    }
2346
    
2347
    @Override
2348
    public Feature findFirst(Expression filter) throws DataException {
2349
        return this.findFirst(filter, (String)null, true);
2350
    }
2351

    
2352
    @Override
2353
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2354
        return this.findFirst(filter, sortBy, true);
2355
    }
2356

    
2357
    @Override
2358
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2359
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2360
        return findFirst(query);
2361
    }
2362
    
2363
    @Override
2364
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2365
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2366
        return findFirst(query);
2367
    }
2368
    
2369
    @Override
2370
    public Feature findFirst(FeatureQuery query) throws DataException {
2371
        if( query == null ) {
2372
            query = this.createFeatureQuery();
2373
        } else {
2374
            query = query.getCopy();
2375
        }
2376
        query.setLimit(1);
2377
        final MutableObject<Feature> feature = new MutableObject<>();
2378
        try {
2379
            this.accept((Object obj) -> {
2380
                feature.setValue((Feature) obj);
2381
                throw new VisitCanceledException();
2382
            }, query);
2383
        } catch(VisitCanceledException ex) {
2384

    
2385
        } catch(DataException ex) {
2386
            throw ex;
2387
        } catch(Exception ex) {
2388
            throw new RuntimeException("", ex);
2389
        }
2390
        return feature.getValue();
2391
    }
2392

    
2393
    @Override
2394
    public void accept(Visitor visitor) throws BaseException {
2395
        this.accept(visitor, null);
2396
    }
2397

    
2398
    @Override
2399
    public void accept(Visitor visitor, DataQuery dataQuery)
2400
        throws BaseException {
2401
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2402
        try {
2403
            set.accept(visitor);
2404
        } finally {
2405
            set.dispose();
2406
        }
2407
    }
2408

    
2409
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2410
        throws DataException {
2411
        DefaultFeatureType fType =
2412
            (DefaultFeatureType) this.getFeatureType(featureQuery
2413
                .getFeatureTypeId());
2414
        if( featureQuery.hasAttributeNames() || 
2415
            featureQuery.hasConstantsAttributeNames() ||
2416
            fType.hasRequiredFields()    
2417
            ) {
2418
            if( featureQuery.hasGroupByColumns()) {
2419
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2420
            } else {
2421
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2422
            }
2423
        }
2424
        return fType;
2425
    }
2426

    
2427
    @Override
2428
    public void getFeatureSet(Observer observer) throws DataException {
2429
        checkNotInAppendMode();
2430
        this.getFeatureSet(null, observer);
2431
    }
2432

    
2433
    @Override
2434
    public void getFeatureSet(FeatureQuery query, Observer observer)
2435
        throws DataException {
2436
        class LoadInBackGround implements Runnable {
2437

    
2438
            private final FeatureStore store;
2439
            private final FeatureQuery query;
2440
            private final Observer observer;
2441

    
2442
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2443
                Observer observer) {
2444
                this.store = store;
2445
                this.query = query;
2446
                this.observer = observer;
2447
            }
2448

    
2449
            void notify(FeatureStoreNotification theNotification) {
2450
                observer.update(store, theNotification);
2451
            }
2452

    
2453
            @Override
2454
            public void run() {
2455
                FeatureSet set = null;
2456
                try {
2457
                    set = store.getFeatureSet(query);
2458
                    notify(new DefaultFeatureStoreNotification(store,
2459
                        FeatureStoreNotification.LOAD_FINISHED, set));
2460
                } catch (Exception e) {
2461
                    notify(new DefaultFeatureStoreNotification(store,
2462
                        FeatureStoreNotification.LOAD_FINISHED, e));
2463
                } finally {
2464
                    dispose(set);
2465
                }
2466
            }
2467
        }
2468

    
2469
        checkNotInAppendMode();
2470
        if (query == null) {
2471
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2472
        }
2473
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2474
        Thread thread = new Thread(task, "Load Feature Set in background");
2475
        thread.start();
2476
    }
2477

    
2478
    @Override
2479
    public Feature getFeatureByReference(FeatureReference reference)
2480
        throws DataException {
2481
        checkNotInAppendMode();
2482
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
2483
        FeatureType featureType;
2484
        if (ref.getFeatureTypeId() == null) {
2485
            featureType = this.getDefaultFeatureType();
2486
        } else {
2487
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2488
        }
2489
        return this.getFeatureByReference(reference, featureType);
2490
    }
2491

    
2492
    @Override
2493
    public Feature getFeatureByReference(FeatureReference reference,
2494
        FeatureType featureType) throws DataException {
2495
        checkNotInAppendMode();
2496
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2497
        if (this.mode == MODE_FULLEDIT) {
2498
            Feature f = featureManager.get(reference, this, featureType);
2499
            if (f != null) {
2500
                return f;
2501
            }
2502
        }
2503

    
2504
        FeatureType sourceFeatureType = featureType;
2505
        if (!this.transforms.isEmpty()) {
2506
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2507
        }
2508
        // TODO comprobar que el id es de este store
2509

    
2510
        DefaultFeature feature =
2511
            new DefaultFeature(this,
2512
                this.provider.getFeatureProviderByReference(
2513
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2514

    
2515
        if (!this.transforms.isEmpty()) {
2516
            return this.transforms.applyTransform(feature, featureType);
2517
        }
2518
        return feature;
2519
    }
2520

    
2521
    //
2522
    // ====================================================================
2523
    // Gestion de features
2524
    //
2525

    
2526
    private FeatureType fixFeatureType(DefaultFeatureType type)
2527
        throws DataException {
2528
        FeatureType original = this.getDefaultFeatureType();
2529

    
2530
        if ((type == null) || type.equals(original)) {
2531
            return original;
2532
        } else {
2533
            if (!type.isSubtypeOf(original)) {
2534
                Iterator iter = this.getFeatureTypes().iterator();
2535
                FeatureType tmpType;
2536
                boolean found = false;
2537
                while (iter.hasNext()) {
2538
                    tmpType = (FeatureType) iter.next();
2539
                    if (type.equals(tmpType)) {
2540
                        return type;
2541

    
2542
                    } else
2543
                        if (type.isSubtypeOf(tmpType)) {
2544
                            found = true;
2545
                            original = tmpType;
2546
                            break;
2547
                        }
2548

    
2549
                }
2550
                if (!found) {
2551
                    throw new IllegalFeatureTypeException(getName());
2552
                }
2553
            }
2554
        }
2555

    
2556
        // Checks that type has all fields of pk
2557
        // else add the missing attributes at the end.
2558
        if (!original.hasOID()) {
2559
            // Gets original pk attributes
2560
            DefaultEditableFeatureType edOriginal =
2561
                (DefaultEditableFeatureType) original.getEditable();
2562
            FeatureAttributeDescriptor orgAttr;
2563
            Iterator edOriginalIter = edOriginal.iterator();
2564
            while (edOriginalIter.hasNext()) {
2565
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2566
                if (!orgAttr.isPrimaryKey()) {
2567
                    edOriginalIter.remove();
2568
                }
2569
            }
2570

    
2571
            // Checks if all pk attributes are in type
2572
            Iterator typeIterator;
2573
            edOriginalIter = edOriginal.iterator();
2574
            FeatureAttributeDescriptor attr;
2575
            while (edOriginalIter.hasNext()) {
2576
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2577
                typeIterator = type.iterator();
2578
                while (typeIterator.hasNext()) {
2579
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2580
                    if (attr.getName().equals(orgAttr.getName())) {
2581
                        edOriginalIter.remove();
2582
                        break;
2583
                    }
2584
                }
2585
            }
2586

    
2587
            // add missing pk attributes if any
2588
            if (edOriginal.size() > 0) {
2589
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2590
                DefaultEditableFeatureType edType =
2591
                    (DefaultEditableFeatureType) original.getEditable();
2592
                edType.clear();
2593
                edType.addAll(type);
2594
                edType.addAll(edOriginal);
2595
                if (!isEditable) {
2596
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2597
                }
2598
            }
2599

    
2600
        }
2601

    
2602
        return type;
2603
    }
2604

    
2605
    @Override
2606
    public void validateFeatures(int mode) throws DataException {
2607
        FeatureSet collection = null;
2608
        DisposableIterator iter = null;
2609
        try {
2610
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2611
            if( rules==null || rules.isEmpty() ) {
2612
                return;
2613
            }
2614
            checkNotInAppendMode();
2615
            collection = this.getFeatureSet();
2616
            iter = collection.fastIterator();
2617
            long previousVersionOfUpdate = currentVersionOfUpdate();
2618
            while (iter.hasNext()) {
2619
                ((DefaultFeature) iter.next()).validate(mode);
2620
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2621
                    throw new ConcurrentDataModificationException(getName());
2622
                }
2623
            }
2624
        } catch (Exception e) {
2625
            throw new ValidateFeaturesException(e, getName());
2626
        } finally {
2627
            DisposeUtils.disposeQuietly(iter);
2628
            DisposeUtils.disposeQuietly(collection);
2629
        }
2630
    }
2631

    
2632
    @Override
2633
    public FeatureType getDefaultFeatureType() throws DataException {
2634
        try {
2635

    
2636
            if (isEditing()) {
2637
                FeatureType auxFeatureType =
2638
                    featureTypeManager.getType(defaultFeatureType.getId());
2639
                if (auxFeatureType != null) {
2640
                    return avoidEditable(auxFeatureType);
2641
                }
2642
            }
2643
            FeatureType type = this.transforms.getDefaultFeatureType();
2644
                if (type != null) {
2645
                return avoidEditable(type);
2646
                }
2647

    
2648
            return avoidEditable(defaultFeatureType);
2649

    
2650
        } catch (Exception e) {
2651
            throw new GetFeatureTypeException(e, getName());
2652
        }
2653
    }
2654

    
2655
    @Override
2656
    public FeatureType getDefaultFeatureTypeQuietly() {
2657
      try {
2658
        return this.getDefaultFeatureType();
2659
      } catch(Exception ex) {
2660
        return null;
2661
      }
2662
    }
2663
    
2664
    private FeatureType avoidEditable(FeatureType ft) {
2665
        if (ft instanceof EditableFeatureType) {
2666
            return ((EditableFeatureType) ft).getNotEditableCopy();
2667
        } else {
2668
            return ft;
2669
        }
2670
    }
2671

    
2672
    @Override
2673
    public FeatureType getFeatureType(String featureTypeId)
2674
        throws DataException {
2675
        if (featureTypeId == null) {
2676
            return this.getDefaultFeatureType();
2677
        }
2678
        try {
2679
            if (isEditing()) {
2680
                FeatureType auxFeatureType =
2681
                    featureTypeManager.getType(featureTypeId);
2682
                if (auxFeatureType != null) {
2683
                    return auxFeatureType;
2684
                }
2685
            }
2686
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2687
            if (type != null) {
2688
                return type;
2689
            }
2690
            Iterator iter = this.featureTypes.iterator();
2691
            while (iter.hasNext()) {
2692
                type = (FeatureType) iter.next();
2693
                if (type.getId().equals(featureTypeId)) {
2694
                    return type;
2695
                }
2696
            }
2697
            return null;
2698
        } catch (Exception e) {
2699
            throw new GetFeatureTypeException(e, getName());
2700
        }
2701
    }
2702

    
2703
    public FeatureType getProviderDefaultFeatureType() {
2704
        return defaultFeatureType;
2705
    }
2706

    
2707
    @Override
2708
    public List getFeatureTypes() throws DataException {
2709
        try {
2710
            List types;
2711
            if (isEditing()) {
2712
                types = new ArrayList();
2713
                for (FeatureType type : featureTypes) {
2714
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2715
                    if (typeaux != null) {
2716
                        types.add(typeaux);
2717
                    } else {
2718
                        types.add(type);
2719
                    }
2720
                }
2721
                Iterator it = featureTypeManager.newsIterator();
2722
                while (it.hasNext()) {
2723
                    FeatureType type = (FeatureType) it.next();
2724
                    types.add(type);
2725
                }
2726
            } else {
2727
                types = this.transforms.getFeatureTypes();
2728
                if (types == null) {
2729
                    types = featureTypes;
2730
                }
2731
            }
2732
            return Collections.unmodifiableList(types);
2733
        } catch (Exception e) {
2734
            throw new GetFeatureTypeException(e, getName());
2735
        }
2736
    }
2737

    
2738
    public List getProviderFeatureTypes() throws DataException {
2739
        return Collections.unmodifiableList(this.featureTypes);
2740
    }
2741

    
2742
    @Override
2743
    public Feature createFeature(FeatureProvider data) throws DataException {
2744
        DefaultFeature feature = new DefaultFeature(this, data);
2745
        return feature;
2746
    }
2747

    
2748
    public Feature createFeature(FeatureProvider data, FeatureType type)
2749
        throws DataException {
2750
        // FIXME: falta por implementar
2751
        // Comprobar si es un subtipo del feature de data
2752
        // y construir un feature usando el subtipo.
2753
        // Probablemente requiera generar una copia del data.
2754
        throw new NotYetImplemented();
2755
    }
2756

    
2757
    @Override
2758
    public EditableFeature createNewFeature(FeatureType type,
2759
        Feature defaultValues) throws DataException {
2760
        try {
2761
            FeatureProvider data = createNewFeatureProvider(type);
2762
            DefaultEditableFeature feature =
2763
                new DefaultEditableFeature(this, data);
2764
            feature.initializeValues(defaultValues);
2765
            data.setNew(true);
2766

    
2767
            return feature;
2768
        } catch (Exception e) {
2769
            throw new CreateFeatureException(e, getName());
2770
        }
2771
    }
2772

    
2773
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2774
        throws DataException {
2775
        type = this.fixFeatureType((DefaultFeatureType) type);
2776
        FeatureProvider data = this.provider.createFeatureProvider(type);
2777
        data.setNew(true);
2778
        if (type.hasOID() && (data.getOID() == null)) {
2779
            data.setOID(this.provider.createNewOID());
2780
        } else {
2781
            data.setOID(this.getTemporalOID());
2782
        }
2783
        return data;
2784

    
2785
    }
2786

    
2787
    @Override
2788
    public EditableFeature createNewFeature(FeatureType type,
2789
        boolean defaultValues) throws DataException {
2790
        try {
2791
            FeatureProvider data = createNewFeatureProvider(type);
2792
            DefaultEditableFeature feature =
2793
                new DefaultEditableFeature(this, data);
2794
            if (defaultValues) {
2795
                feature.initializeValues();
2796
            }
2797
            return feature;
2798
        } catch (Exception e) {
2799
            throw new CreateFeatureException(e, getName());
2800
        }
2801
    }
2802

    
2803
    @Override
2804
    public EditableFeature createNewFeature(boolean defaultValues)
2805
        throws DataException {
2806
        return this.createNewFeature(this.getDefaultFeatureType(),
2807
            defaultValues);
2808
    }
2809

    
2810
    @Override
2811
    public EditableFeature createNewFeature() throws DataException {
2812
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2813
    }
2814

    
2815
    @Override
2816
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2817
        FeatureType ft = this.getDefaultFeatureType();
2818
        EditableFeature f = this.createNewFeature(ft, false);
2819
        f.copyFrom(defaultValues);
2820
        return f;
2821
    }
2822

    
2823
    @Override
2824
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2825
        FeatureType ft = this.getDefaultFeatureType();
2826
        EditableFeature f = this.createNewFeature(ft, false);
2827
        f.copyFrom(defaultValues);
2828
        return f;
2829
    }
2830

    
2831
    @Override
2832
    public EditableFeatureType createFeatureType() {
2833
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2834
        return ftype;
2835
    }
2836

    
2837
    @Override
2838
    public EditableFeatureType createFeatureType(String id) {
2839
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2840
        return ftype;
2841
    }
2842

    
2843
    //
2844
    // ====================================================================
2845
    // Index related methods
2846
    //
2847

    
2848
    @Override
2849
    public FeatureIndexes getIndexes() {
2850
        return this.indexes;
2851
    }
2852

    
2853
    @Override
2854
    public FeatureIndex createIndex(FeatureType featureType,
2855
        String attributeName, String indexName) throws DataException {
2856
        return createIndex(null, featureType, attributeName, indexName);
2857
    }
2858

    
2859
    @Override
2860
    public FeatureIndex createIndex(String indexTypeName,
2861
        FeatureType featureType, String attributeName, String indexName)
2862
        throws DataException {
2863

    
2864
        return createIndex(indexTypeName, featureType, attributeName,
2865
            indexName, false, null);
2866
    }
2867

    
2868
    @Override
2869
    public FeatureIndex createIndex(FeatureType featureType,
2870
        String attributeName, String indexName, Observer observer)
2871
        throws DataException {
2872
        return createIndex(null, featureType, attributeName, indexName,
2873
            observer);
2874
    }
2875

    
2876
    @Override
2877
    public FeatureIndex createIndex(String indexTypeName,
2878
        FeatureType featureType, String attributeName, String indexName,
2879
        final Observer observer) throws DataException {
2880

    
2881
        return createIndex(indexTypeName, featureType, attributeName,
2882
            indexName, true, observer);
2883
    }
2884

    
2885
    private FeatureIndex createIndex(String indexTypeName,
2886
        FeatureType featureType, String attributeName, String indexName,
2887
        boolean background, final Observer observer) throws DataException {
2888

    
2889
        checkNotInAppendMode();
2890
        FeatureIndexProviderServices index;
2891
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2892
                featureType, indexName,
2893
                featureType.getAttributeDescriptor(attributeName));
2894

    
2895
        try {
2896
            index.fill(background, observer);
2897
        } catch (FeatureIndexException e) {
2898
            throw new InitializeException(index.getName(), e);
2899
        }
2900

    
2901
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2902
        return index;
2903
    }
2904

    
2905
    //
2906
    // ====================================================================
2907
    // Transforms related methods
2908
    //
2909

    
2910
    @Override
2911
    public FeatureStoreTransforms getTransforms() {
2912
        return this.transforms;
2913
    }
2914

    
2915
    @Override
2916
    public FeatureQuery createFeatureQuery() {
2917
        return new DefaultFeatureQuery();
2918
    }
2919
    
2920
    @Override
2921
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
2922
        FeatureQuery query = null;
2923
        if( filter!=null ) {
2924
            query = this.createFeatureQuery();
2925
            query.setFilter(filter);
2926
        }
2927
        if( !StringUtils.isBlank(sortBy) ) {
2928
            if( query == null ) {
2929
                query = this.createFeatureQuery();
2930
            }
2931
            if ( StringUtils.containsAny(sortBy, "(", ")") ) {
2932
                throw new IllegalArgumentException("Incorrect sortBy expression");
2933
            }
2934
            String[] attrnames;
2935
            if( sortBy.contains(",") ) {
2936
                attrnames = StringUtils.split(sortBy, ",");
2937
            } else {
2938
                attrnames = new String[] { sortBy };
2939
            }
2940
            for (String attrname : attrnames) {
2941
                attrname = attrname.trim();
2942
                if( attrname.startsWith("-") ) {
2943
                    query.getOrder().add(attrname.substring(1).trim(), false);
2944
                } else if( attrname.endsWith("-") ) { 
2945
                    query.getOrder().add(attrname.substring(0,sortBy.length()-1).trim(), false);
2946
                } else if( attrname.startsWith("+") ) {
2947
                    query.getOrder().add(attrname.substring(1).trim(), true);
2948
                } else if( attrname.endsWith("-") ) { 
2949
                    query.getOrder().add(attrname.substring(0,sortBy.length()-1).trim(), true);
2950
                } else {
2951
                    query.getOrder().add(attrname, asc);
2952
                }
2953
            }
2954
        }
2955
        if( query != null ) {
2956
            query.retrievesAllAttributes();
2957
        }
2958
        return query;
2959
    }
2960
    
2961
    @Override
2962
    public FeatureQuery createFeatureQuery(String filter) {
2963
        return this.createFeatureQuery(
2964
                ExpressionUtils.createExpression(filter), 
2965
                (String)null, 
2966
                true
2967
        );
2968
    }
2969
    
2970
    @Override
2971
    public FeatureQuery createFeatureQuery(Expression filter) {
2972
        return this.createFeatureQuery(
2973
                filter, 
2974
                (String)null, 
2975
                true
2976
        );
2977
    }
2978
    
2979
    @Override
2980
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
2981
        if( StringUtils.isBlank(filter) ) {
2982
            return this.createFeatureQuery(
2983
                    (Expression)null, 
2984
                    sortBy, 
2985
                    asc
2986
            );
2987
        } else {
2988
            return this.createFeatureQuery(
2989
                    ExpressionUtils.createExpression(filter), 
2990
                    sortBy, 
2991
                    asc
2992
            );
2993
        }
2994
    }
2995
    
2996
    @Override
2997
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
2998
        FeatureQuery query = null;
2999
        if( filter != null ) {
3000
            query = this.createFeatureQuery();
3001
            query.setFilter(filter);
3002
        }
3003
        if( sortBy !=  null) {
3004
            if( query == null ) {
3005
                query = this.createFeatureQuery();
3006
            }
3007
            query.getOrder().add(sortBy, asc);
3008
        }
3009
        
3010
        if( query != null ) {
3011
            query.retrievesAllAttributes();
3012
        }
3013
        return query;
3014
    }
3015
    
3016
    @Override
3017
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3018
        if( StringUtils.isBlank(filter) ) {
3019
            return this.createFeatureQuery(
3020
                    (Expression)null, 
3021
                    sortBy, 
3022
                    asc
3023
            );
3024
        } else {
3025
            return this.createFeatureQuery(
3026
                    ExpressionUtils.createExpression(filter), 
3027
                    sortBy, 
3028
                    asc
3029
            );
3030
        }
3031
    }
3032
    
3033
    @Override
3034
    public DataQuery createQuery() {
3035
        return createFeatureQuery();
3036
    }
3037

    
3038
    //
3039
    // ====================================================================
3040
    // UndoRedo related methods
3041
    //
3042

    
3043
    @Override
3044
    public boolean canRedo() {
3045
        return commands.canRedo();
3046
    }
3047

    
3048
    @Override
3049
    public boolean canUndo() {
3050
        return commands.canUndo();
3051
    }
3052

    
3053
    @Override
3054
    public void redo(int num) throws RedoException {
3055
        for (int i = 0; i < num; i++) {
3056
            redo();
3057
        }
3058
    }
3059

    
3060
    @Override
3061
    public void undo(int num) throws UndoException {
3062
        for (int i = 0; i < num; i++) {
3063
            undo();
3064
        }
3065
    }
3066

    
3067
    //
3068
    // ====================================================================
3069
    // Metadata related methods
3070
    //
3071

    
3072
    @Override
3073
    public Object getMetadataID() {
3074
        return this.provider.getSourceId();
3075
    }
3076

    
3077
    @Override
3078
    public void delegate(DynObject dynObject) {
3079
        this.metadata.delegate(dynObject);
3080
    }
3081

    
3082
    @Override
3083
    public DynClass getDynClass() {
3084
        return this.metadata.getDynClass();
3085
    }
3086

    
3087
    @Override
3088
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3089
        try {
3090
            if (this.transforms.hasDynValue(name)) {
3091
                return this.transforms.getDynValue(name);
3092
            }
3093
            if (this.metadata.hasDynValue(name)) {
3094
                return this.metadata.getDynValue(name);
3095
            }
3096
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3097
                return this.provider.getProviderName();
3098
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3099
                return this.provider.getSourceId();
3100
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3101
                try {
3102
                    return this.getDefaultFeatureType();
3103
                } catch (DataException e) {
3104
                    return null;
3105
                }
3106
            }
3107
            return this.metadata.getDynValue(name);
3108
        } catch(Exception ex ) {
3109
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
3110
            return null;
3111
        }
3112
    }
3113

    
3114
    @Override
3115
    public boolean hasDynValue(String name) {
3116
        if (this.transforms.hasDynValue(name)) {
3117
            return true;
3118
        }
3119
        return this.metadata.hasDynValue(name);
3120
    }
3121

    
3122
    @Override
3123
    public boolean hasDynMethod(String name) {
3124
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
3125
    }
3126

    
3127
    @Override
3128
    public void implement(DynClass dynClass) {
3129
        this.metadata.implement(dynClass);
3130
    }
3131

    
3132
    @Override
3133
    public Object invokeDynMethod(String name, Object[] args)
3134
        throws DynMethodException {
3135
        return this.metadata.invokeDynMethod(this, name, args);
3136
    }
3137

    
3138
    @Override
3139
    public Object invokeDynMethod(int code, Object[] args)
3140
        throws DynMethodException {
3141
        return this.metadata.invokeDynMethod(this, code, args);
3142
    }
3143

    
3144
    @Override
3145
    public void setDynValue(String name, Object value)
3146
        throws DynFieldNotFoundException {
3147
                if( this.transforms.hasDynValue(name) ) {
3148
                        this.transforms.setDynValue(name, value);
3149
                        return;
3150
                }
3151
        this.metadata.setDynValue(name, value);
3152

    
3153
    }
3154

    
3155
    /*
3156
     * (non-Javadoc)
3157
     *
3158
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3159
     */
3160
    @Override
3161
    public Set getMetadataChildren() {
3162
        return this.metadataChildren;
3163
    }
3164

    
3165
    /*
3166
     * (non-Javadoc)
3167
     *
3168
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3169
     */
3170
    @Override
3171
    public String getMetadataName() {
3172
        return this.provider.getProviderName();
3173
    }
3174

    
3175
    public FeatureTypeManager getFeatureTypeManager() {
3176
        return this.featureTypeManager;
3177
    }
3178

    
3179
    @Override
3180
    public long getFeatureCount() throws DataException {
3181
        if (featureCount == null) {
3182
            featureCount = this.provider.getFeatureCount();
3183
        }
3184
        if (this.isEditing()) {
3185
            if(this.isAppending()) {
3186
                try{
3187
                    throw new IllegalStateException();
3188
                } catch(IllegalStateException e) {
3189
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
3190
                }
3191
                return -1;
3192
            } else {
3193
                return featureCount
3194
                    + this.featureManager.getDeltaSize();
3195
            }
3196
        }
3197
        return featureCount;
3198
    }
3199

    
3200
    private Long getTemporalOID() {
3201
        return this.temporalOid++;
3202
    }
3203

    
3204
    @Override
3205
    public FeatureType getProviderFeatureType(String featureTypeId) {
3206
        if (featureTypeId == null) {
3207
            return this.defaultFeatureType;
3208
        }
3209
        FeatureType type;
3210
        Iterator iter = this.featureTypes.iterator();
3211
        while (iter.hasNext()) {
3212
            type = (FeatureType) iter.next();
3213
            if (type.getId().equals(featureTypeId)) {
3214
                return type;
3215
            }
3216
        }
3217
        return null;
3218
    }
3219

    
3220
    @Override
3221
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3222
        return ((DefaultFeature) feature).getData();
3223
    }
3224

    
3225
    @Override
3226
    public DataStore getStore() {
3227
        return this;
3228
    }
3229

    
3230
    @Override
3231
    public FeatureStore getFeatureStore() {
3232
        return this;
3233
    }
3234

    
3235
    @Override
3236
    public void createCache(String name, DynObject parameters)
3237
        throws DataException {
3238
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3239
        if (cache == null) {
3240
            throw new CreateException("FeaureCacheProvider", null);
3241
        }
3242
        cache.apply(this, provider);
3243
        provider = cache;
3244

    
3245
        featureCount = null;
3246
    }
3247

    
3248
    @Override
3249
    public FeatureCache getCache() {
3250
        return cache;
3251
    }
3252

    
3253
    @Override
3254
    public void clear() {
3255
        if (metadata != null) {
3256
            metadata.clear();
3257
        }
3258
    }
3259

    
3260
    @Override
3261
    public String getName() {
3262
        if( this.provider != null ) {
3263
            return this.provider.getName();
3264
        }
3265
        if( this.parameters instanceof HasAFile ) {
3266
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
3267
        }
3268
        return "unknow";
3269
    }
3270

    
3271
    @Override
3272
    public String getFullName() {
3273
        try {
3274
            if( this.provider!=null ) {
3275
                return this.provider.getFullName();
3276
            }
3277
            if( this.parameters instanceof HasAFile ) {
3278
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
3279
            }
3280
            return null;
3281
        } catch(Throwable th) {
3282
            return null;
3283
        }
3284
    }
3285

    
3286
    @Override
3287
    public String getProviderName() {
3288
        if( this.provider!=null ) {
3289
            return this.provider.getProviderName();
3290
        }
3291
        if( this.parameters != null ) {
3292
            return this.parameters.getDataStoreName();
3293
        }
3294
        return null;
3295

    
3296
    }
3297

    
3298
    @Override
3299
    public boolean isKnownEnvelope() {
3300
        return this.provider.isKnownEnvelope();
3301
    }
3302

    
3303
    @Override
3304
    public boolean hasRetrievedFeaturesLimit() {
3305
        return this.provider.hasRetrievedFeaturesLimit();
3306
    }
3307

    
3308
    @Override
3309
    public int getRetrievedFeaturesLimit() {
3310
        return this.provider.getRetrievedFeaturesLimit();
3311
    }
3312

    
3313
    @Override
3314
    public Interval getInterval() {
3315
        if( this.timeSupport!=null ) {
3316
            return this.timeSupport.getInterval();
3317
        }
3318
        try {
3319
            FeatureType type = this.getDefaultFeatureType();
3320
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3321
            if( attr!=null ) {
3322
                Interval interval = attr.getInterval();
3323
                if( interval!=null ) {
3324
                    return interval;
3325
                }
3326
            }
3327
        } catch (DataException ex) {
3328
        }
3329
        return this.provider.getInterval();
3330
    }
3331

    
3332
    @Override
3333
    public Collection getTimes() {
3334
        if( this.timeSupport!=null ) {
3335
            return this.timeSupport.getTimes();
3336
        }
3337
        return this.provider.getTimes();
3338
    }
3339

    
3340
    @Override
3341
    public Collection getTimes(Interval interval) {
3342
        if( this.timeSupport!=null ) {
3343
            return this.timeSupport.getTimes(interval);
3344
        }
3345
        return this.provider.getTimes(interval);
3346
    }
3347

    
3348
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3349
        if( this.isEditing() ) {
3350
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
3351
        }
3352
        if( !this.transforms.isEmpty() ) {
3353
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
3354
        }
3355
        FeatureType ft = this.defaultFeatureType;
3356
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3357
        if( attr == null ) {
3358
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
3359
        }
3360
        EditableFeatureType eft = ft.getEditable();
3361
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3362
        if( attr != null ) {
3363
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
3364
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
3365
            }
3366
            eft.remove(attr.getName());
3367
        }
3368
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3369
            timeSupport.getAttributeName(), 
3370
            timeSupport.getDataType()
3371
        );
3372
        attrTime.setIsTime(true);
3373
        attrTime.setFeatureAttributeEmulator(timeSupport);
3374
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3375
        this.defaultFeatureType = eft.getNotEditableCopy();
3376
        
3377
        this.timeSupport = timeSupport;
3378
    }
3379

    
3380
    @Override
3381
    @SuppressWarnings("CloneDoesntCallSuperClone")
3382
    public Object clone() throws CloneNotSupportedException {
3383

    
3384
        DataStoreParameters dsp = getParameters();
3385

    
3386
        DefaultFeatureStore cloned_store = null;
3387

    
3388
        try {
3389
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3390
                openStore(this.getProviderName(), dsp);
3391
            if (transforms != null) {
3392
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3393
                cloned_store.transforms.setStoreForClone(cloned_store);
3394
            }
3395
        } catch (Exception e) {
3396
            throw new CloneException(e);
3397
        }
3398
        return cloned_store;
3399

    
3400
    }
3401

    
3402
    @Override
3403
    public Feature getFeature(DynObject dynobject) {
3404
        if (dynobject instanceof DynObjectFeatureFacade){
3405
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
3406
            return f;
3407
        }
3408
        return null;
3409
    }
3410

    
3411
    @Override
3412
    public Iterator iterator() {
3413
        FeatureSet fset = null;
3414
        try {
3415
            fset  = this.getFeatureSet();
3416
            return fset.fastIterator();
3417
        } catch (DataException ex) {
3418
            throw new RuntimeException(ex);
3419
        } finally {
3420
            DisposeUtils.disposeQuietly(fset);
3421
        }
3422
    }
3423

    
3424
    @Override
3425
    public long size64() {
3426
        FeatureSet fset = null;
3427
        try {
3428
            fset  = this.getFeatureSet();
3429
            return fset.getSize();
3430
        } catch (DataException ex) {
3431
            throw new RuntimeException(ex);
3432
        } finally {
3433
            DisposeUtils.disposeQuietly(fset);
3434
        }
3435
    }
3436
   
3437
    @Override
3438
    public ExpressionBuilder createExpressionBuilder() {
3439
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3440
        return builder;
3441
    }
3442

    
3443
    @Override
3444
    public ExpressionBuilder createExpression() {
3445
        return createExpressionBuilder();
3446
    }
3447

    
3448
    public FeatureSet features() throws DataException {
3449
        // This is to avoid jython to create a property with this name
3450
        // to access method getFeatures.
3451
        return this.getFeatureSet();
3452
    }
3453

    
3454
    @Override
3455
    public DataStoreProviderFactory getProviderFactory() {
3456
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3457
        return factory;
3458
    }
3459

    
3460
    @Override
3461
    public void useCache(String providerName, DynObject parameters) throws DataException {
3462
        throw new UnsupportedOperationException();
3463
    }
3464

    
3465
    @Override
3466
    public boolean isBroken() {
3467
        return this.state.isBroken();
3468
    }
3469

    
3470
    @Override
3471
    public Throwable getBreakingsCause() {
3472
            return this.state.getBreakingsCause();
3473
    }
3474

    
3475
    @Override
3476
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3477
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3478
      if( !factory.supportNumericOID() ) {
3479
          return null;
3480
      }
3481
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3482
      return wrappedIndex;
3483
  }
3484

    
3485
    @Override
3486
    public FeatureReference getFeatureReference(String code) {
3487
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
3488
        return featureReference;
3489
    }
3490

    
3491
    @Override
3492
    public long getPendingChangesCount() {
3493
        if( this.featureManager==null ) {
3494
            return 0;
3495
        }
3496
        return this.featureManager.getPendingChangesCount();
3497
    }
3498

    
3499
    @Override
3500
    public ResourcesStorage getResourcesStorage() {
3501
        ResourcesStorage resourcesStorage;
3502
        try {
3503
            resourcesStorage = this.provider.getResourcesStorage();
3504
            if( resourcesStorage!=null ) {
3505
                return resourcesStorage;
3506
            }
3507
        } catch(Throwable th) {
3508
            
3509
        }
3510
        try {
3511
            DataServerExplorer explorer = this.getExplorer();
3512
            if( explorer==null ) {
3513
                return null;
3514
            }
3515
            resourcesStorage = explorer.getResourcesStorage(this);
3516
            explorer.dispose();
3517
            return resourcesStorage;
3518
        } catch (Exception ex) {
3519
            LOGGER.trace("Can't create resources storage",ex);
3520
            return null;
3521
        }
3522
    }
3523

    
3524
    @Override
3525
    public StoresRepository getStoresRepository() {
3526
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3527
        StoresRepository localRepository = this.provider.getStoresRepository();
3528
        if( localRepository==null ) {
3529
            return mainRepository;
3530
        }
3531
        StoresRepository repository = new BaseStoresRepository(this.getName());
3532
        repository.addRepository(localRepository);
3533
        repository.addRepository(mainRepository);
3534
        return repository;
3535
    }
3536

    
3537
    @Override
3538
    public Feature getSampleFeature() {
3539
            Feature sampleFeature;
3540
            try {
3541
                FeatureSelection theSelection = this.getFeatureSelection();
3542
                if( theSelection!=null && !theSelection.isEmpty() ) {
3543
                    sampleFeature = theSelection.first();
3544
                } else {
3545
                    sampleFeature = this.first();
3546
                }
3547
                if( sampleFeature==null ) {
3548
                    sampleFeature = this.createNewFeature();
3549
                }
3550
            } catch (DataException ex) {
3551
                return null;
3552
            }
3553
            return sampleFeature;
3554
    }
3555

    
3556
    @Override
3557
    public boolean supportReferences() {
3558
        try {
3559
            return this.getDefaultFeatureType().supportReferences();
3560
        } catch (Exception ex) {
3561
            return false;
3562
        }
3563
    }
3564

    
3565
    @Override
3566
    public boolean isTemporary() {
3567
        if( this.provider==null ) {
3568
            return true;
3569
        }
3570
        return this.provider.isTemporary();
3571
    }
3572
    
3573
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3574
        // FIXME this don't work for Store.fType.size() > 1
3575
        FeatureTypeManager manager = this.featureTypeManager;
3576
         if (manager==null) {
3577
             return null;
3578
         }
3579
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3580
         if (originalFeatureType==null) {
3581
             return null;
3582
         }
3583
         return originalFeatureType.getCopy();
3584
    }
3585

    
3586
    @Override
3587
    public Object getProperty(String name) {
3588
        if( this.propertiesSupportHelper==null ) {
3589
            return null;
3590
        }
3591
        return this.propertiesSupportHelper.getProperty(name);
3592
    }
3593

    
3594
    @Override
3595
    public void setProperty(String name, Object value) {
3596
        if( this.propertiesSupportHelper==null ) {
3597
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3598
        }
3599
        this.propertiesSupportHelper.setProperty(name,value);
3600
    }
3601

    
3602
    @Override
3603
    public Map<String, Object> getProperties() {
3604
        if( this.propertiesSupportHelper==null ) {
3605
            return Collections.EMPTY_MAP;
3606
        }
3607
        return this.propertiesSupportHelper.getProperties();
3608
    }
3609
    
3610
    @Override
3611
    public Feature getOriginalFeature(FeatureReference id){
3612
        if(this.featureManager == null){
3613
            return null;
3614
        }
3615
        return featureManager.getOriginal(id);
3616
    }
3617

    
3618
    @Override
3619
    public Feature getOriginalFeature(Feature feature){
3620
        if(feature == null){
3621
            return null;
3622
        }
3623
        return getOriginalFeature(feature.getReference());
3624
    }
3625

    
3626
    @Override
3627
    public boolean isFeatureModified(FeatureReference id){
3628
        if(this.featureManager == null){
3629
            return false;
3630
        }
3631
        return featureManager.isFeatureModified(id);
3632
    }
3633

    
3634
    @Override
3635
    public boolean isFeatureModified(Feature feature){
3636
        if(feature == null){
3637
            return false;
3638
        }
3639
        return isFeatureModified(feature.getReference());
3640
    }
3641

    
3642

    
3643
}