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

History | View | Annotate | Download (122 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.exception.AlreadyEditingException;
95
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
96
import org.gvsig.fmap.dal.feature.exception.CreateFeatureException;
97
import org.gvsig.fmap.dal.feature.exception.DataExportException;
98
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
99
import org.gvsig.fmap.dal.feature.exception.FinishEditingException;
100
import org.gvsig.fmap.dal.feature.exception.GetFeatureTypeException;
101
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureException;
102
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureTypeException;
103
import org.gvsig.fmap.dal.feature.exception.NeedEditingModeException;
104
import org.gvsig.fmap.dal.feature.exception.NoNewFeatureInsertException;
105
import org.gvsig.fmap.dal.feature.exception.NullFeatureTypeException;
106
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
107
import org.gvsig.fmap.dal.feature.exception.PersistenceCantFindFeatureTypeException;
108
import org.gvsig.fmap.dal.feature.exception.PersistenceStoreAlreadyLoadedException;
109
import org.gvsig.fmap.dal.feature.exception.SelectionNotAllowedException;
110
import org.gvsig.fmap.dal.feature.exception.StoreCancelEditingException;
111
import org.gvsig.fmap.dal.feature.exception.StoreDeleteEditableFeatureException;
112
import org.gvsig.fmap.dal.feature.exception.StoreDeleteFeatureException;
113
import org.gvsig.fmap.dal.feature.exception.StoreEditException;
114
import org.gvsig.fmap.dal.feature.exception.StoreInsertFeatureException;
115
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureException;
116
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureTypeException;
117
import org.gvsig.fmap.dal.feature.exception.ValidateFeaturesException;
118
import org.gvsig.fmap.dal.feature.exception.WriteNotAllowedException;
119
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
120
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureManager;
121
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureTypeManager;
122
import org.gvsig.fmap.dal.feature.impl.editing.memory.SpatialManager;
123
import org.gvsig.fmap.dal.feature.impl.featureset.DefaultFeatureSet;
124
import org.gvsig.fmap.dal.feature.impl.undo.DefaultFeatureCommandsStack;
125
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
126
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
127
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
128
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
129
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
130
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
131
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
132
import org.gvsig.fmap.dal.feature.spi.cache.FeatureCacheProvider;
133
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProviderServices;
134
import org.gvsig.fmap.dal.impl.DefaultDataManager;
135
import org.gvsig.fmap.dal.resource.Resource;
136
import org.gvsig.fmap.dal.spi.AbstractDataStore;
137
import org.gvsig.fmap.dal.spi.DataStoreInitializer2;
138
import org.gvsig.fmap.dal.spi.DataStoreProvider;
139
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
140
import org.gvsig.fmap.geom.Geometry;
141
import org.gvsig.fmap.geom.SpatialIndex;
142
import org.gvsig.fmap.geom.primitive.Envelope;
143
import org.gvsig.metadata.MetadataLocator;
144
import org.gvsig.metadata.MetadataManager;
145
import org.gvsig.metadata.exceptions.MetadataException;
146
import org.gvsig.timesupport.Interval;
147
import org.gvsig.tools.ToolsLocator;
148
import org.gvsig.tools.dispose.DisposableIterator;
149
import org.gvsig.tools.dispose.DisposeUtils;
150
import org.gvsig.tools.dynobject.DelegatedDynObject;
151
import org.gvsig.tools.dynobject.DynClass;
152
import org.gvsig.tools.dynobject.DynObject;
153
import org.gvsig.tools.dynobject.DynObjectManager;
154
import org.gvsig.tools.dynobject.DynObject_v2;
155
import org.gvsig.tools.dynobject.DynStruct;
156
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
157
import org.gvsig.tools.dynobject.exception.DynMethodException;
158
import org.gvsig.tools.exception.BaseException;
159
import org.gvsig.tools.exception.NotYetImplemented;
160
import org.gvsig.tools.identitymanagement.SimpleIdentityManager;
161
import org.gvsig.tools.observer.Observable;
162
import org.gvsig.tools.observer.Observer;
163
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
164
import org.gvsig.tools.persistence.PersistenceManager;
165
import org.gvsig.tools.persistence.Persistent;
166
import org.gvsig.tools.persistence.PersistentState;
167
import org.gvsig.tools.persistence.exception.PersistenceException;
168
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
169
import org.gvsig.tools.undo.RedoException;
170
import org.gvsig.tools.undo.UndoException;
171
import org.gvsig.tools.undo.command.Command;
172
import org.gvsig.tools.util.GetItemWithSizeIsEmptyAndIterator64;
173
import org.gvsig.tools.util.HasAFile;
174
import org.gvsig.tools.util.PropertiesSupportHelper;
175
import org.gvsig.tools.util.UnmodifiableBasicMap;
176
import org.gvsig.tools.visitor.VisitCanceledException;
177
import org.gvsig.tools.visitor.Visitor;
178

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

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

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

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

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

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

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

    
209
    private DefaultDataManager dataManager = null;
210

    
211
    private FeatureStoreProvider provider = null;
212

    
213
    private DefaultFeatureIndexes indexes;
214

    
215
    private DefaultFeatureStoreTransforms transforms;
216

    
217
    /*friend*/ DelegatedDynObject metadata;
218

    
219
    private Set metadataChildren;
220

    
221
    private Long featureCount = null;
222

    
223
    private long temporalOid = 0;
224

    
225
    private FeatureCacheProvider cache;
226

    
227
    private final StateInformation state;
228

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

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

    
235
        private static final long serialVersionUID = 4109026189635185666L;
236

    
237
        private boolean broken;
238
        private Throwable breakingsCause;
239

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

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

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

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

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

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

    
272

    
273

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

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

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

    
296
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
297

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

    
303
        this.dataManager = (DefaultDataManager) dataManager;
304

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

    
313
    }
314

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

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

    
352
    public int getMode() {
353
        return this.mode;
354
    }
355

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

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

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

    
375
    public FeatureManager getFeatureManager() {
376
        return this.featureManager;
377
    }
378

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

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

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

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

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

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

    
468
        this.featureManager = null;
469
        this.spatialManager = null;
470

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

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

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

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

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

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

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

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

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

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

    
620
        }
621

    
622
        if (evaluatedAttr.isEmpty()) {
623
            evaluatedAttr = null;
624
        }
625

    
626
        state.set("evaluatedAttributes", evaluatedAttr);
627
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
628

    
629
    }
630

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

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

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

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

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

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

    
743
                    }
744

    
745
            }
746
        } catch(Throwable th) {
747
            state.setBreakingsCause(th);
748
        }
749

    
750

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

    
755
            if (defaultFeatureType == null ||
756
                    defaultFeatureType.getId() == null ||
757
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
758

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

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

    
783
    public DataStoreProviderServices getStoreProviderServices() {
784
        return this;
785
    }
786

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

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

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

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

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

    
813
            definition.addDynFieldString("defaultFeatureTypeId")
814
                .setMandatory(true).setPersistent(true);
815
        }
816
    }
817

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

    
828
    //
829
    // ====================================================================
830
    // Gestion de la seleccion
831
    //
832

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

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

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

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

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

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

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

    
907
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
908
    }
909

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

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

    
939
    //
940
    // ====================================================================
941
    // Gestion de notificaciones
942
    //
943

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

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

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

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

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

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

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

    
1005
    //
1006
    // ====================================================================
1007
    // Gestion de bloqueos
1008
    //
1009

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

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

    
1027
    //
1028
    // ====================================================================
1029
    // Interface Observable
1030
    //
1031

    
1032
    @Override
1033
    public void disableNotifications() {
1034
        this.delegateObservable.disableNotifications();
1035

    
1036
    }
1037

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

    
1043
    @Override
1044
    public void beginComplexNotification() {
1045
        this.delegateObservable.beginComplexNotification();
1046

    
1047
    }
1048

    
1049
    @Override
1050
    public void endComplexNotification() {
1051
        this.delegateObservable.endComplexNotification();
1052

    
1053
    }
1054

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

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

    
1069
    @Override
1070
    public void deleteObservers() {
1071
        this.delegateObservable.deleteObservers();
1072

    
1073
    }
1074

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

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

    
1094
        } else if (observable instanceof FeatureStoreProvider) {
1095
            if (observable == this.provider) {
1096

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

    
1105
    //
1106
    // ====================================================================
1107
    // Edicion
1108
    //
1109

    
1110
    private void newVersionOfUpdate() {
1111
        this.versionOfUpdate++;
1112
    }
1113

    
1114
    private long currentVersionOfUpdate() {
1115
        return this.versionOfUpdate;
1116
    }
1117

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

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

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

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

    
1146
        if (featureTypeManager != null) {
1147
            featureTypeManager.dispose();
1148
            featureTypeManager = null;
1149

    
1150
        }
1151

    
1152
        // TODO implementar un dispose para estos dos
1153
        featureManager = null;
1154
        spatialManager = null;
1155

    
1156
        featureCount = null;
1157

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

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

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

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

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

    
1238
    private void invalidateIndexes() {
1239
        setIndexesValidStatus(false);
1240
    }
1241

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

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

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

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

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

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

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

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

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

    
1440
            //Update the featureManager and the spatialManager
1441
            featureManager.delete(feature.getReference());
1442
            spatialManager.deleteFeature(feature);
1443

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

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

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

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

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

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

    
1517
    synchronized public void doInsert(EditableFeature feature)
1518
        throws DataException {
1519
        checkIsOwnFeature(feature);
1520

    
1521
        waitForIndexes();
1522

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

    
1537

    
1538
        featureManager.add(newFeature);
1539
        spatialManager.insertFeature(newFeature);
1540

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

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

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

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

    
1630
            //Update the featureManager and the spatialManager
1631
            Feature newf = feature.getNotEditableCopy();
1632
            featureManager.update(newf, oldFeature);
1633
            spatialManager.updateFeature(newf, oldFeature);
1634

    
1635
            hasStrongChanges = true;
1636
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1637
        } catch (Exception e) {
1638
            throw new StoreUpdateFeatureException(e, this.getName());
1639
        }
1640
    }
1641

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

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

    
1676
    @Override
1677
    public List getRedoInfos() {
1678
        if (isEditing() && (commands != null)) {
1679
            return commands.getRedoInfos();
1680
        } else {
1681
            return null;
1682
        }
1683
    }
1684

    
1685
    @Override
1686
    public List getUndoInfos() {
1687
        if (isEditing() && (commands != null)) {
1688
            return commands.getUndoInfos();
1689
        } else {
1690
            return null;
1691
        }
1692
    }
1693

    
1694
    public synchronized FeatureCommandsStack getCommandsStack()
1695
        throws DataException {
1696
        checkInEditingMode();
1697
        return commands;
1698
    }
1699

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

    
1721
            case MODE_APPEND:
1722
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1723
                  return;
1724
                }
1725
                provider.abortAppend();
1726
                exitEditingMode();
1727
                ((FeatureSelection) this.getSelection()).deselectAll();
1728
                updateIndexes();
1729
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1730
                break;
1731

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

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

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

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

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

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

    
1825
                    /*
1826
                     * This will throw a PerformEditingExceptionif the provider
1827
                     * does not accept the changes (for example, an invalid field name)
1828
                     */
1829
                    provider.performChanges(featureManager.getDeleted(),
1830
                        featureManager.getInserted(),
1831
                        featureManager.getUpdated(),
1832
                        removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1833
                   
1834
                }  
1835
                this.updateComputedFields(computedFields);
1836
                exitEditingMode();
1837
                loadDALFile();
1838
                updateIndexes();
1839
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1840
                break;
1841
            case MODE_PASS_THROUGH:
1842
                if( selection!=null ) {
1843
                    selection = null;
1844
                }
1845
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled() ) {
1846
                  return;
1847
                }
1848
                exitEditingMode();
1849
                updateIndexes();
1850
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1851
                break;
1852
            }
1853
        } catch (PerformEditingException pee) {
1854
            throw new WriteException(provider.getSourceId().toString(), pee);
1855
        } catch (Exception e) {
1856
            throw new FinishEditingException(e);
1857
        }
1858
    }
1859
    private Map<String,List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
1860
        Map<String,List<FeatureAttributeDescriptor>> r = new HashMap<>();
1861
        
1862
        List<FeatureType> theTypes = new ArrayList<>();
1863
        theTypes.addAll(this.getFeatureTypes());
1864
        theTypes.add(this.getDefaultFeatureType());
1865
        for( int n=0; n<theTypes.size(); n++ ) {
1866
            FeatureType type = theTypes.get(n);
1867
                for (FeatureAttributeDescriptor attrdesc : type) {
1868
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
1869
                    if( emulator!= null) {
1870
                        List<FeatureAttributeDescriptor> l = r.get(type.getId());
1871
                        if (l==null) {
1872
                            l = new ArrayList<>();
1873
                            r.put(type.getId(), l);
1874
                        }
1875
                        l.add(attrdesc);
1876
                    }
1877
            }
1878
        }
1879
        return r;
1880
    }
1881
    private void updateComputedFields(Map<String,List<FeatureAttributeDescriptor>> computedFields) throws DataException {
1882

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

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

    
1977
        case MODE_APPEND:
1978
          this.provider.endAppend();
1979
          exitEditingMode();
1980
          invalidateIndexes();
1981
          this.provider.beginAppend();
1982
          hasInserts = false;
1983
          break;
1984

    
1985
        case MODE_FULLEDIT:
1986
          if (hasStrongChanges && !this.allowWrite()) {
1987
            throw new WriteNotAllowedException(getName());
1988
          }
1989
          if (hasStrongChanges) {
1990
            validateFeatures(Feature.FINISH_EDITING);
1991
            provider.performChanges(featureManager.getDeleted(),
1992
              featureManager.getInserted(),
1993
              featureManager.getUpdated(),
1994
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1995
          }
1996
          invalidateIndexes();
1997
          featureManager = new FeatureManager();
1998
          featureTypeManager = new FeatureTypeManager(this);
1999
          spatialManager = new SpatialManager(this, provider.getEnvelope());
2000

    
2001
          commands =
2002
            new DefaultFeatureCommandsStack(this, featureManager,
2003
              spatialManager, featureTypeManager);
2004
          featureCount = null;
2005
          hasStrongChanges = false;
2006
          hasInserts = false;
2007
          break;
2008
        }
2009
      } catch (Exception e) {
2010
        throw new FinishEditingException(e);
2011
      }
2012
    }
2013

    
2014
    @Override
2015
    synchronized public boolean canCommitChanges() throws DataException {
2016
        if ( !this.allowWrite()) {
2017
                return false;
2018
        }
2019
            switch (mode) {
2020
            default:
2021
        case MODE_QUERY:
2022
                return false;
2023

    
2024
        case MODE_APPEND:
2025
                return true;
2026

    
2027
        case MODE_FULLEDIT:
2028
            List types = this.getFeatureTypes();
2029
            for( int i=0; i<types.size(); i++ ) {
2030
                    Object type = types.get(i);
2031
                    if( type instanceof DefaultEditableFeatureType ) {
2032
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
2033
                                    return false;
2034
                            }
2035
                    }
2036
            }
2037
            return true;
2038
            }
2039
    }
2040

    
2041
    @Override
2042
    public void beginEditingGroup(String description)
2043
        throws NeedEditingModeException {
2044
        checkInEditingMode();
2045
        commands.startComplex(description);
2046
    }
2047

    
2048
    @Override
2049
    public void endEditingGroup() throws NeedEditingModeException {
2050
        checkInEditingMode();
2051
        commands.endComplex();
2052
    }
2053

    
2054
    @Override
2055
    public boolean isAppendModeSupported() {
2056
        return this.provider.supportsAppendMode();
2057
    }
2058

    
2059
    @Override
2060
    public void export(DataServerExplorer explorer, String provider,
2061
        NewFeatureStoreParameters params) throws DataException {
2062

    
2063
        if (this.getFeatureTypes().size() != 1) {
2064
            throw new NotYetImplemented(
2065
                "export whith more than one type not yet implemented");
2066
        }
2067
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2068
        FeatureStore target = null;
2069
        FeatureSet features = null;
2070
        DisposableIterator iterator = null;
2071
        try {
2072
            FeatureType type = this.getDefaultFeatureType();
2073
            if ((params.getDefaultFeatureType() == null)
2074
                || (params.getDefaultFeatureType().size() == 0)) {
2075
                params.setDefaultFeatureType(type.getEditable());
2076

    
2077
            }
2078
            explorer.add(provider, params, true);
2079

    
2080
            DataManager manager = DALLocator.getDataManager();
2081
            target = (FeatureStore) manager.openStore(provider, params);
2082
            FeatureType targetType = target.getDefaultFeatureType();
2083

    
2084
            target.edit(MODE_APPEND);
2085
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2086
            if (featureSelection.getSize() > 0) {
2087
                features = this.getFeatureSelection();
2088
            } else {
2089
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2090
                    FeatureQuery query = createFeatureQuery();
2091
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2092
                        query.getOrder().add(pkattr.getName(), true);
2093
                    }
2094
                    features = this.getFeatureSet(query);
2095
                } else {
2096
                    features = this.getFeatureSet();
2097
                }
2098
            }
2099
            iterator = features.fastIterator();
2100
            while (iterator.hasNext()) {
2101
                DefaultFeature feature = (DefaultFeature) iterator.next();
2102
                target.insert(target.createNewFeature(targetType, feature));
2103
            }
2104
            target.finishEditing();
2105
            target.dispose();
2106
        } catch (Exception e) {
2107
            throw new DataExportException(e, params.toString());
2108
        } finally {
2109
            dispose(iterator);
2110
            dispose(features);
2111
            dispose(target);
2112
        }
2113
    }
2114

    
2115
    @Override
2116
    public void copyTo(final FeatureStore target) {
2117
        boolean finishEditingAtEnd = false;
2118
        try {
2119
            if( !target.isEditing() && !target.isAppending() ) {
2120
                finishEditingAtEnd = true;
2121
                target.edit(MODE_APPEND);
2122
            }
2123
            this.accept((Object obj) -> {
2124
                Feature f_src = (Feature) obj;
2125
                EditableFeature f_dst = target.createNewFeature(f_src);
2126
                target.insert(f_dst);
2127
            });
2128
            if( finishEditingAtEnd ) {
2129
                target.finishEditing();
2130
            }
2131
            
2132
        } catch(Exception ex) {
2133
            try {
2134
                if( finishEditingAtEnd ) {
2135
                    target.cancelEditing();
2136
                }
2137
            } catch (Exception ex1) {
2138
            }
2139
            throw new RuntimeException("Can't copy store.",ex);
2140
        }
2141
            
2142
    }
2143
    
2144
    //
2145
    // ====================================================================
2146
    // Obtencion de datos
2147
    // getDataCollection, getFeatureCollection
2148
    //
2149

    
2150
    @Override
2151
    public DataSet getDataSet() throws DataException {
2152
        checkNotInAppendMode();
2153
        FeatureQuery query =
2154
            new DefaultFeatureQuery(this.getDefaultFeatureType());
2155
        return new DefaultFeatureSet(this, query);
2156
    }
2157

    
2158
    @Override
2159
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2160
        checkNotInAppendMode();
2161
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2162
    }
2163

    
2164
    @Override
2165
    public void getDataSet(Observer observer) throws DataException {
2166
        checkNotInAppendMode();
2167
        this.getFeatureSet(null, observer);
2168
    }
2169

    
2170
    @Override
2171
    public void getDataSet(DataQuery dataQuery, Observer observer)
2172
        throws DataException {
2173
        checkNotInAppendMode();
2174
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2175
    }
2176

    
2177
    @Override
2178
    public FeatureSet getFeatureSet() throws DataException {
2179
        return this.getFeatureSet((FeatureQuery)null);
2180
    }
2181

    
2182
    @Override
2183
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2184
        throws DataException {
2185
        checkNotInAppendMode();
2186
        if( featureQuery==null ) {
2187
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2188
        }
2189
        return new DefaultFeatureSet(this, featureQuery);
2190
    }
2191

    
2192
    @Override
2193
    public FeatureSet getFeatureSet(String filter) throws DataException {
2194
        return this.getFeatureSet(filter, null, true);
2195
    }
2196

    
2197
    @Override
2198
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2199
        return this.getFeatureSet(filter, sortBy, true);
2200
    }
2201

    
2202
    @Override
2203
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2204
        return this.getFeatureSet(filter, null, true);
2205
    }
2206
    
2207
    @Override
2208
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2209
        return this.getFeatureSet(filter, sortBy, true);
2210
    }
2211

    
2212
    @Override
2213
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2214
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2215
        return this.getFeatureSet(query);
2216
    }
2217
    
2218
    @Override
2219
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2220
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2221
        return this.getFeatureSet(query);
2222
    }
2223
    
2224
    @Override
2225
    public List<Feature> getFeatures(String filter)  {
2226
        return this.getFeatures(filter, null, true);
2227
    }
2228

    
2229
    @Override
2230
    public List<Feature> getFeatures(String filter, String sortBy)  {
2231
        return this.getFeatures(filter, sortBy, true);
2232
    }
2233

    
2234
    @Override
2235
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
2236
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2237
        return this.getFeatures(query, 0);
2238
    }
2239
    
2240
    @Override
2241
    public List<Feature> getFeatures(Expression filter)  {
2242
        return this.getFeatures(filter, null, true);
2243
    }
2244

    
2245
    @Override
2246
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
2247
        return this.getFeatures(filter, sortBy, true);
2248
    }
2249

    
2250
    @Override
2251
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
2252
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2253
        return this.getFeatures(query, 0);
2254
    }
2255
    
2256
    @Override
2257
    public List<Feature> getFeatures(FeatureQuery query)  {
2258
        return this.getFeatures(query, 0);
2259
    }
2260
    
2261
    @Override
2262
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
2263
        try {
2264
            if( pageSize<=0 ) {
2265
                pageSize = 100;
2266
            }
2267
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2268
            return pager.asList();
2269
        } catch (BaseException ex) {
2270
            throw new RuntimeException("Can't create the list of features.", ex);
2271
        }
2272
    }
2273

    
2274
    @Override
2275
    public List<Feature> getFeatures() {
2276
        return this.getFeatures(null, 0);
2277
    }
2278

    
2279
    @Override
2280
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2281
        return this.getFeatures64(null, 0);
2282
    }
2283

    
2284
    @Override
2285
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2286
        return this.getFeatures64(filter, null, true);
2287
    }
2288
    
2289
    @Override
2290
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc)  {
2291
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2292
        return this.getFeatures64(query, 0);
2293
    }
2294

    
2295
    @Override
2296
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize)  {
2297
        try {
2298
            if( pageSize<=0 ) {
2299
                pageSize = 100;
2300
            }
2301
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2302
            return pager;
2303
        } catch (BaseException ex) {
2304
            throw new RuntimeException("Can't create the list of features.", ex);
2305
        }
2306
    }
2307

    
2308
    @Override
2309
    public Feature first() throws DataException {
2310
        return this.findFirst((FeatureQuery)null);
2311
    }
2312
    
2313
    @Override
2314
    public Feature findFirst(String filter) throws DataException {
2315
        return this.findFirst(filter, (String)null, true);
2316
    }
2317

    
2318
    @Override
2319
    public Feature findFirst(String filter, String sortBy) throws DataException {
2320
        return this.findFirst(filter, sortBy, true);
2321
    }
2322

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

    
2329
    @Override
2330
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2331
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2332
        return findFirst(query);
2333
    }
2334
    
2335
    @Override
2336
    public Feature findFirst(Expression filter) throws DataException {
2337
        return this.findFirst(filter, (String)null, true);
2338
    }
2339

    
2340
    @Override
2341
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2342
        return this.findFirst(filter, sortBy, true);
2343
    }
2344

    
2345
    @Override
2346
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2347
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2348
        return findFirst(query);
2349
    }
2350
    
2351
    @Override
2352
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2353
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2354
        return findFirst(query);
2355
    }
2356
    
2357
    @Override
2358
    public Feature findFirst(FeatureQuery query) throws DataException {
2359
        if( query == null ) {
2360
            query = this.createFeatureQuery();
2361
        } else {
2362
            query = query.getCopy();
2363
        }
2364
        query.setLimit(1);
2365
        final MutableObject<Feature> feature = new MutableObject<>();
2366
        try {
2367
            this.accept((Object obj) -> {
2368
                feature.setValue((Feature) obj);
2369
                throw new VisitCanceledException();
2370
            }, query);
2371
        } catch(VisitCanceledException ex) {
2372

    
2373
        } catch(DataException ex) {
2374
            throw ex;
2375
        } catch(Exception ex) {
2376
            throw new RuntimeException("", ex);
2377
        }
2378
        return feature.getValue();
2379
    }
2380

    
2381
    @Override
2382
    public void accept(Visitor visitor) throws BaseException {
2383
        this.accept(visitor, null);
2384
    }
2385

    
2386
    @Override
2387
    public void accept(Visitor visitor, DataQuery dataQuery)
2388
        throws BaseException {
2389
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2390
        try {
2391
            set.accept(visitor);
2392
        } finally {
2393
            set.dispose();
2394
        }
2395
    }
2396

    
2397
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2398
        throws DataException {
2399
        DefaultFeatureType fType =
2400
            (DefaultFeatureType) this.getFeatureType(featureQuery
2401
                .getFeatureTypeId());
2402
        if( featureQuery.hasAttributeNames() || 
2403
            featureQuery.hasConstantsAttributeNames() ||
2404
            fType.hasRequiredFields()    
2405
            ) {
2406
            if( featureQuery.hasGroupByColumns()) {
2407
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2408
            } else {
2409
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2410
            }
2411
        }
2412
        return fType;
2413
    }
2414

    
2415
    @Override
2416
    public void getFeatureSet(Observer observer) throws DataException {
2417
        checkNotInAppendMode();
2418
        this.getFeatureSet(null, observer);
2419
    }
2420

    
2421
    @Override
2422
    public void getFeatureSet(FeatureQuery query, Observer observer)
2423
        throws DataException {
2424
        class LoadInBackGround implements Runnable {
2425

    
2426
            private final FeatureStore store;
2427
            private final FeatureQuery query;
2428
            private final Observer observer;
2429

    
2430
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2431
                Observer observer) {
2432
                this.store = store;
2433
                this.query = query;
2434
                this.observer = observer;
2435
            }
2436

    
2437
            void notify(FeatureStoreNotification theNotification) {
2438
                observer.update(store, theNotification);
2439
            }
2440

    
2441
            @Override
2442
            public void run() {
2443
                FeatureSet set = null;
2444
                try {
2445
                    set = store.getFeatureSet(query);
2446
                    notify(new DefaultFeatureStoreNotification(store,
2447
                        FeatureStoreNotification.LOAD_FINISHED, set));
2448
                } catch (Exception e) {
2449
                    notify(new DefaultFeatureStoreNotification(store,
2450
                        FeatureStoreNotification.LOAD_FINISHED, e));
2451
                } finally {
2452
                    dispose(set);
2453
                }
2454
            }
2455
        }
2456

    
2457
        checkNotInAppendMode();
2458
        if (query == null) {
2459
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2460
        }
2461
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2462
        Thread thread = new Thread(task, "Load Feature Set in background");
2463
        thread.start();
2464
    }
2465

    
2466
    @Override
2467
    public Feature getFeatureByReference(FeatureReference reference)
2468
        throws DataException {
2469
        checkNotInAppendMode();
2470
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
2471
        FeatureType featureType;
2472
        if (ref.getFeatureTypeId() == null) {
2473
            featureType = this.getDefaultFeatureType();
2474
        } else {
2475
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2476
        }
2477
        return this.getFeatureByReference(reference, featureType);
2478
    }
2479

    
2480
    @Override
2481
    public Feature getFeatureByReference(FeatureReference reference,
2482
        FeatureType featureType) throws DataException {
2483
        checkNotInAppendMode();
2484
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2485
        if (this.mode == MODE_FULLEDIT) {
2486
            Feature f = featureManager.get(reference, this, featureType);
2487
            if (f != null) {
2488
                return f;
2489
            }
2490
        }
2491

    
2492
        FeatureType sourceFeatureType = featureType;
2493
        if (!this.transforms.isEmpty()) {
2494
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2495
        }
2496
        // TODO comprobar que el id es de este store
2497

    
2498
        DefaultFeature feature =
2499
            new DefaultFeature(this,
2500
                this.provider.getFeatureProviderByReference(
2501
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2502

    
2503
        if (!this.transforms.isEmpty()) {
2504
            return this.transforms.applyTransform(feature, featureType);
2505
        }
2506
        return feature;
2507
    }
2508

    
2509
    //
2510
    // ====================================================================
2511
    // Gestion de features
2512
    //
2513

    
2514
    private FeatureType fixFeatureType(DefaultFeatureType type)
2515
        throws DataException {
2516
        FeatureType original = this.getDefaultFeatureType();
2517

    
2518
        if ((type == null) || type.equals(original)) {
2519
            return original;
2520
        } else {
2521
            if (!type.isSubtypeOf(original)) {
2522
                Iterator iter = this.getFeatureTypes().iterator();
2523
                FeatureType tmpType;
2524
                boolean found = false;
2525
                while (iter.hasNext()) {
2526
                    tmpType = (FeatureType) iter.next();
2527
                    if (type.equals(tmpType)) {
2528
                        return type;
2529

    
2530
                    } else
2531
                        if (type.isSubtypeOf(tmpType)) {
2532
                            found = true;
2533
                            original = tmpType;
2534
                            break;
2535
                        }
2536

    
2537
                }
2538
                if (!found) {
2539
                    throw new IllegalFeatureTypeException(getName());
2540
                }
2541
            }
2542
        }
2543

    
2544
        // Checks that type has all fields of pk
2545
        // else add the missing attributes at the end.
2546
        if (!original.hasOID()) {
2547
            // Gets original pk attributes
2548
            DefaultEditableFeatureType edOriginal =
2549
                (DefaultEditableFeatureType) original.getEditable();
2550
            FeatureAttributeDescriptor orgAttr;
2551
            Iterator edOriginalIter = edOriginal.iterator();
2552
            while (edOriginalIter.hasNext()) {
2553
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2554
                if (!orgAttr.isPrimaryKey()) {
2555
                    edOriginalIter.remove();
2556
                }
2557
            }
2558

    
2559
            // Checks if all pk attributes are in type
2560
            Iterator typeIterator;
2561
            edOriginalIter = edOriginal.iterator();
2562
            FeatureAttributeDescriptor attr;
2563
            while (edOriginalIter.hasNext()) {
2564
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2565
                typeIterator = type.iterator();
2566
                while (typeIterator.hasNext()) {
2567
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2568
                    if (attr.getName().equals(orgAttr.getName())) {
2569
                        edOriginalIter.remove();
2570
                        break;
2571
                    }
2572
                }
2573
            }
2574

    
2575
            // add missing pk attributes if any
2576
            if (edOriginal.size() > 0) {
2577
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2578
                DefaultEditableFeatureType edType =
2579
                    (DefaultEditableFeatureType) original.getEditable();
2580
                edType.clear();
2581
                edType.addAll(type);
2582
                edType.addAll(edOriginal);
2583
                if (!isEditable) {
2584
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2585
                }
2586
            }
2587

    
2588
        }
2589

    
2590
        return type;
2591
    }
2592

    
2593
    @Override
2594
    public void validateFeatures(int mode) throws DataException {
2595
        FeatureSet collection = null;
2596
        DisposableIterator iter = null;
2597
        try {
2598
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2599
            if( rules==null || rules.isEmpty() ) {
2600
                return;
2601
            }
2602
            checkNotInAppendMode();
2603
            collection = this.getFeatureSet();
2604
            iter = collection.fastIterator();
2605
            long previousVersionOfUpdate = currentVersionOfUpdate();
2606
            while (iter.hasNext()) {
2607
                ((DefaultFeature) iter.next()).validate(mode);
2608
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2609
                    throw new ConcurrentDataModificationException(getName());
2610
                }
2611
            }
2612
        } catch (Exception e) {
2613
            throw new ValidateFeaturesException(e, getName());
2614
        } finally {
2615
            DisposeUtils.disposeQuietly(iter);
2616
            DisposeUtils.disposeQuietly(collection);
2617
        }
2618
    }
2619

    
2620
    @Override
2621
    public FeatureType getDefaultFeatureType() throws DataException {
2622
        try {
2623

    
2624
            if (isEditing()) {
2625
                FeatureType auxFeatureType =
2626
                    featureTypeManager.getType(defaultFeatureType.getId());
2627
                if (auxFeatureType != null) {
2628
                    return avoidEditable(auxFeatureType);
2629
                }
2630
            }
2631
            FeatureType type = this.transforms.getDefaultFeatureType();
2632
                if (type != null) {
2633
                return avoidEditable(type);
2634
                }
2635

    
2636
            return avoidEditable(defaultFeatureType);
2637

    
2638
        } catch (Exception e) {
2639
            throw new GetFeatureTypeException(e, getName());
2640
        }
2641
    }
2642

    
2643
    @Override
2644
    public FeatureType getDefaultFeatureTypeQuietly() {
2645
      try {
2646
        return this.getDefaultFeatureType();
2647
      } catch(Exception ex) {
2648
        return null;
2649
      }
2650
    }
2651
    
2652
    private FeatureType avoidEditable(FeatureType ft) {
2653
        if (ft instanceof EditableFeatureType) {
2654
            return ((EditableFeatureType) ft).getNotEditableCopy();
2655
        } else {
2656
            return ft;
2657
        }
2658
    }
2659

    
2660
    @Override
2661
    public FeatureType getFeatureType(String featureTypeId)
2662
        throws DataException {
2663
        if (featureTypeId == null) {
2664
            return this.getDefaultFeatureType();
2665
        }
2666
        try {
2667
            if (isEditing()) {
2668
                FeatureType auxFeatureType =
2669
                    featureTypeManager.getType(featureTypeId);
2670
                if (auxFeatureType != null) {
2671
                    return auxFeatureType;
2672
                }
2673
            }
2674
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2675
            if (type != null) {
2676
                return type;
2677
            }
2678
            Iterator iter = this.featureTypes.iterator();
2679
            while (iter.hasNext()) {
2680
                type = (FeatureType) iter.next();
2681
                if (type.getId().equals(featureTypeId)) {
2682
                    return type;
2683
                }
2684
            }
2685
            return null;
2686
        } catch (Exception e) {
2687
            throw new GetFeatureTypeException(e, getName());
2688
        }
2689
    }
2690

    
2691
    public FeatureType getProviderDefaultFeatureType() {
2692
        return defaultFeatureType;
2693
    }
2694

    
2695
    @Override
2696
    public List getFeatureTypes() throws DataException {
2697
        try {
2698
            List types;
2699
            if (isEditing()) {
2700
                types = new ArrayList();
2701
                for (FeatureType type : featureTypes) {
2702
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2703
                    if (typeaux != null) {
2704
                        types.add(typeaux);
2705
                    } else {
2706
                        types.add(type);
2707
                    }
2708
                }
2709
                Iterator it = featureTypeManager.newsIterator();
2710
                while (it.hasNext()) {
2711
                    FeatureType type = (FeatureType) it.next();
2712
                    types.add(type);
2713
                }
2714
            } else {
2715
                types = this.transforms.getFeatureTypes();
2716
                if (types == null) {
2717
                    types = featureTypes;
2718
                }
2719
            }
2720
            return Collections.unmodifiableList(types);
2721
        } catch (Exception e) {
2722
            throw new GetFeatureTypeException(e, getName());
2723
        }
2724
    }
2725

    
2726
    public List getProviderFeatureTypes() throws DataException {
2727
        return Collections.unmodifiableList(this.featureTypes);
2728
    }
2729

    
2730
    @Override
2731
    public Feature createFeature(FeatureProvider data) throws DataException {
2732
        DefaultFeature feature = new DefaultFeature(this, data);
2733
        return feature;
2734
    }
2735

    
2736
    public Feature createFeature(FeatureProvider data, FeatureType type)
2737
        throws DataException {
2738
        // FIXME: falta por implementar
2739
        // Comprobar si es un subtipo del feature de data
2740
        // y construir un feature usando el subtipo.
2741
        // Probablemente requiera generar una copia del data.
2742
        throw new NotYetImplemented();
2743
    }
2744

    
2745
    @Override
2746
    public EditableFeature createNewFeature(FeatureType type,
2747
        Feature defaultValues) throws DataException {
2748
        try {
2749
            FeatureProvider data = createNewFeatureProvider(type);
2750
            DefaultEditableFeature feature =
2751
                new DefaultEditableFeature(this, data);
2752
            feature.initializeValues(defaultValues);
2753
            data.setNew(true);
2754

    
2755
            return feature;
2756
        } catch (Exception e) {
2757
            throw new CreateFeatureException(e, getName());
2758
        }
2759
    }
2760

    
2761
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2762
        throws DataException {
2763
        type = this.fixFeatureType((DefaultFeatureType) type);
2764
        FeatureProvider data = this.provider.createFeatureProvider(type);
2765
        data.setNew(true);
2766
        if (type.hasOID() && (data.getOID() == null)) {
2767
            data.setOID(this.provider.createNewOID());
2768
        } else {
2769
            data.setOID(this.getTemporalOID());
2770
        }
2771
        return data;
2772

    
2773
    }
2774

    
2775
    @Override
2776
    public EditableFeature createNewFeature(FeatureType type,
2777
        boolean defaultValues) throws DataException {
2778
        try {
2779
            FeatureProvider data = createNewFeatureProvider(type);
2780
            DefaultEditableFeature feature =
2781
                new DefaultEditableFeature(this, data);
2782
            if (defaultValues) {
2783
                feature.initializeValues();
2784
            }
2785
            return feature;
2786
        } catch (Exception e) {
2787
            throw new CreateFeatureException(e, getName());
2788
        }
2789
    }
2790

    
2791
    @Override
2792
    public EditableFeature createNewFeature(boolean defaultValues)
2793
        throws DataException {
2794
        return this.createNewFeature(this.getDefaultFeatureType(),
2795
            defaultValues);
2796
    }
2797

    
2798
    @Override
2799
    public EditableFeature createNewFeature() throws DataException {
2800
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2801
    }
2802

    
2803
    @Override
2804
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2805
        FeatureType ft = this.getDefaultFeatureType();
2806
        EditableFeature f = this.createNewFeature(ft, false);
2807
        f.copyFrom(defaultValues);
2808
        return f;
2809
    }
2810

    
2811
    @Override
2812
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2813
        FeatureType ft = this.getDefaultFeatureType();
2814
        EditableFeature f = this.createNewFeature(ft, false);
2815
        f.copyFrom(defaultValues);
2816
        return f;
2817
    }
2818

    
2819
    @Override
2820
    public EditableFeatureType createFeatureType() {
2821
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2822
        return ftype;
2823
    }
2824

    
2825
    @Override
2826
    public EditableFeatureType createFeatureType(String id) {
2827
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2828
        return ftype;
2829
    }
2830

    
2831
    //
2832
    // ====================================================================
2833
    // Index related methods
2834
    //
2835

    
2836
    @Override
2837
    public FeatureIndexes getIndexes() {
2838
        return this.indexes;
2839
    }
2840

    
2841
    @Override
2842
    public FeatureIndex createIndex(FeatureType featureType,
2843
        String attributeName, String indexName) throws DataException {
2844
        return createIndex(null, featureType, attributeName, indexName);
2845
    }
2846

    
2847
    @Override
2848
    public FeatureIndex createIndex(String indexTypeName,
2849
        FeatureType featureType, String attributeName, String indexName)
2850
        throws DataException {
2851

    
2852
        return createIndex(indexTypeName, featureType, attributeName,
2853
            indexName, false, null);
2854
    }
2855

    
2856
    @Override
2857
    public FeatureIndex createIndex(FeatureType featureType,
2858
        String attributeName, String indexName, Observer observer)
2859
        throws DataException {
2860
        return createIndex(null, featureType, attributeName, indexName,
2861
            observer);
2862
    }
2863

    
2864
    @Override
2865
    public FeatureIndex createIndex(String indexTypeName,
2866
        FeatureType featureType, String attributeName, String indexName,
2867
        final Observer observer) throws DataException {
2868

    
2869
        return createIndex(indexTypeName, featureType, attributeName,
2870
            indexName, true, observer);
2871
    }
2872

    
2873
    private FeatureIndex createIndex(String indexTypeName,
2874
        FeatureType featureType, String attributeName, String indexName,
2875
        boolean background, final Observer observer) throws DataException {
2876

    
2877
        checkNotInAppendMode();
2878
        FeatureIndexProviderServices index;
2879
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2880
                featureType, indexName,
2881
                featureType.getAttributeDescriptor(attributeName));
2882

    
2883
        try {
2884
            index.fill(background, observer);
2885
        } catch (FeatureIndexException e) {
2886
            throw new InitializeException(index.getName(), e);
2887
        }
2888

    
2889
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2890
        return index;
2891
    }
2892

    
2893
    //
2894
    // ====================================================================
2895
    // Transforms related methods
2896
    //
2897

    
2898
    @Override
2899
    public FeatureStoreTransforms getTransforms() {
2900
        return this.transforms;
2901
    }
2902

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

    
3026
    //
3027
    // ====================================================================
3028
    // UndoRedo related methods
3029
    //
3030

    
3031
    @Override
3032
    public boolean canRedo() {
3033
        return commands.canRedo();
3034
    }
3035

    
3036
    @Override
3037
    public boolean canUndo() {
3038
        return commands.canUndo();
3039
    }
3040

    
3041
    @Override
3042
    public void redo(int num) throws RedoException {
3043
        for (int i = 0; i < num; i++) {
3044
            redo();
3045
        }
3046
    }
3047

    
3048
    @Override
3049
    public void undo(int num) throws UndoException {
3050
        for (int i = 0; i < num; i++) {
3051
            undo();
3052
        }
3053
    }
3054

    
3055
    //
3056
    // ====================================================================
3057
    // Metadata related methods
3058
    //
3059

    
3060
    @Override
3061
    public Object getMetadataID() {
3062
        return this.provider.getSourceId();
3063
    }
3064

    
3065
    @Override
3066
    public void delegate(DynObject dynObject) {
3067
        this.metadata.delegate(dynObject);
3068
    }
3069

    
3070
    @Override
3071
    public DynClass getDynClass() {
3072
        return this.metadata.getDynClass();
3073
    }
3074

    
3075
    @Override
3076
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3077
        try {
3078
            if (this.transforms.hasDynValue(name)) {
3079
                return this.transforms.getDynValue(name);
3080
            }
3081
            if (this.metadata.hasDynValue(name)) {
3082
                return this.metadata.getDynValue(name);
3083
            }
3084
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3085
                return this.provider.getProviderName();
3086
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3087
                return this.provider.getSourceId();
3088
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3089
                try {
3090
                    return this.getDefaultFeatureType();
3091
                } catch (DataException e) {
3092
                    return null;
3093
                }
3094
            }
3095
            return this.metadata.getDynValue(name);
3096
        } catch(Exception ex ) {
3097
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
3098
            return null;
3099
        }
3100
    }
3101

    
3102
    @Override
3103
    public boolean hasDynValue(String name) {
3104
        if (this.transforms.hasDynValue(name)) {
3105
            return true;
3106
        }
3107
        return this.metadata.hasDynValue(name);
3108
    }
3109

    
3110
    @Override
3111
    public boolean hasDynMethod(String name) {
3112
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
3113
    }
3114

    
3115
    @Override
3116
    public void implement(DynClass dynClass) {
3117
        this.metadata.implement(dynClass);
3118
    }
3119

    
3120
    @Override
3121
    public Object invokeDynMethod(String name, Object[] args)
3122
        throws DynMethodException {
3123
        return this.metadata.invokeDynMethod(this, name, args);
3124
    }
3125

    
3126
    @Override
3127
    public Object invokeDynMethod(int code, Object[] args)
3128
        throws DynMethodException {
3129
        return this.metadata.invokeDynMethod(this, code, args);
3130
    }
3131

    
3132
    @Override
3133
    public void setDynValue(String name, Object value)
3134
        throws DynFieldNotFoundException {
3135
                if( this.transforms.hasDynValue(name) ) {
3136
                        this.transforms.setDynValue(name, value);
3137
                        return;
3138
                }
3139
        this.metadata.setDynValue(name, value);
3140

    
3141
    }
3142

    
3143
    /*
3144
     * (non-Javadoc)
3145
     *
3146
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3147
     */
3148
    @Override
3149
    public Set getMetadataChildren() {
3150
        return this.metadataChildren;
3151
    }
3152

    
3153
    /*
3154
     * (non-Javadoc)
3155
     *
3156
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3157
     */
3158
    @Override
3159
    public String getMetadataName() {
3160
        return this.provider.getProviderName();
3161
    }
3162

    
3163
    public FeatureTypeManager getFeatureTypeManager() {
3164
        return this.featureTypeManager;
3165
    }
3166

    
3167
    @Override
3168
    public long getFeatureCount() throws DataException {
3169
        if (featureCount == null) {
3170
            featureCount = this.provider.getFeatureCount();
3171
        }
3172
        if (this.isEditing()) {
3173
            if(this.isAppending()) {
3174
                try{
3175
                    throw new IllegalStateException();
3176
                } catch(IllegalStateException e) {
3177
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
3178
                }
3179
                return -1;
3180
            } else {
3181
                return featureCount
3182
                    + this.featureManager.getDeltaSize();
3183
            }
3184
        }
3185
        return featureCount;
3186
    }
3187

    
3188
    private Long getTemporalOID() {
3189
        return this.temporalOid++;
3190
    }
3191

    
3192
    @Override
3193
    public FeatureType getProviderFeatureType(String featureTypeId) {
3194
        if (featureTypeId == null) {
3195
            return this.defaultFeatureType;
3196
        }
3197
        FeatureType type;
3198
        Iterator iter = this.featureTypes.iterator();
3199
        while (iter.hasNext()) {
3200
            type = (FeatureType) iter.next();
3201
            if (type.getId().equals(featureTypeId)) {
3202
                return type;
3203
            }
3204
        }
3205
        return null;
3206
    }
3207

    
3208
    @Override
3209
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3210
        return ((DefaultFeature) feature).getData();
3211
    }
3212

    
3213
    @Override
3214
    public DataStore getStore() {
3215
        return this;
3216
    }
3217

    
3218
    @Override
3219
    public FeatureStore getFeatureStore() {
3220
        return this;
3221
    }
3222

    
3223
    @Override
3224
    public void createCache(String name, DynObject parameters)
3225
        throws DataException {
3226
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3227
        if (cache == null) {
3228
            throw new CreateException("FeaureCacheProvider", null);
3229
        }
3230
        cache.apply(this, provider);
3231
        provider = cache;
3232

    
3233
        featureCount = null;
3234
    }
3235

    
3236
    @Override
3237
    public FeatureCache getCache() {
3238
        return cache;
3239
    }
3240

    
3241
    @Override
3242
    public void clear() {
3243
        if (metadata != null) {
3244
            metadata.clear();
3245
        }
3246
    }
3247

    
3248
    @Override
3249
    public String getName() {
3250
        if( this.provider != null ) {
3251
            return this.provider.getName();
3252
        }
3253
        if( this.parameters instanceof HasAFile ) {
3254
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
3255
        }
3256
        return "unknow";
3257
    }
3258

    
3259
    @Override
3260
    public String getFullName() {
3261
        try {
3262
            if( this.provider!=null ) {
3263
                return this.provider.getFullName();
3264
            }
3265
            if( this.parameters instanceof HasAFile ) {
3266
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
3267
            }
3268
            return null;
3269
        } catch(Throwable th) {
3270
            return null;
3271
        }
3272
    }
3273

    
3274
    @Override
3275
    public String getProviderName() {
3276
        if( this.provider!=null ) {
3277
            return this.provider.getProviderName();
3278
        }
3279
        if( this.parameters != null ) {
3280
            return this.parameters.getDataStoreName();
3281
        }
3282
        return null;
3283

    
3284
    }
3285

    
3286
    @Override
3287
    public boolean isKnownEnvelope() {
3288
        return this.provider.isKnownEnvelope();
3289
    }
3290

    
3291
    @Override
3292
    public boolean hasRetrievedFeaturesLimit() {
3293
        return this.provider.hasRetrievedFeaturesLimit();
3294
    }
3295

    
3296
    @Override
3297
    public int getRetrievedFeaturesLimit() {
3298
        return this.provider.getRetrievedFeaturesLimit();
3299
    }
3300

    
3301
    @Override
3302
    public Interval getInterval() {
3303
        if( this.timeSupport!=null ) {
3304
            return this.timeSupport.getInterval();
3305
        }
3306
        try {
3307
            FeatureType type = this.getDefaultFeatureType();
3308
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3309
            if( attr!=null ) {
3310
                Interval interval = attr.getInterval();
3311
                if( interval!=null ) {
3312
                    return interval;
3313
                }
3314
            }
3315
        } catch (DataException ex) {
3316
        }
3317
        return this.provider.getInterval();
3318
    }
3319

    
3320
    @Override
3321
    public Collection getTimes() {
3322
        if( this.timeSupport!=null ) {
3323
            return this.timeSupport.getTimes();
3324
        }
3325
        return this.provider.getTimes();
3326
    }
3327

    
3328
    @Override
3329
    public Collection getTimes(Interval interval) {
3330
        if( this.timeSupport!=null ) {
3331
            return this.timeSupport.getTimes(interval);
3332
        }
3333
        return this.provider.getTimes(interval);
3334
    }
3335

    
3336
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3337
        if( this.isEditing() ) {
3338
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
3339
        }
3340
        if( !this.transforms.isEmpty() ) {
3341
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
3342
        }
3343
        FeatureType ft = this.defaultFeatureType;
3344
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3345
        if( attr == null ) {
3346
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
3347
        }
3348
        EditableFeatureType eft = ft.getEditable();
3349
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3350
        if( attr != null ) {
3351
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
3352
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
3353
            }
3354
            eft.remove(attr.getName());
3355
        }
3356
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3357
            timeSupport.getAttributeName(), 
3358
            timeSupport.getDataType()
3359
        );
3360
        attrTime.setIsTime(true);
3361
        attrTime.setFeatureAttributeEmulator(timeSupport);
3362
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3363
        this.defaultFeatureType = eft.getNotEditableCopy();
3364
        
3365
        this.timeSupport = timeSupport;
3366
    }
3367

    
3368
    @Override
3369
    @SuppressWarnings("CloneDoesntCallSuperClone")
3370
    public Object clone() throws CloneNotSupportedException {
3371

    
3372
        DataStoreParameters dsp = getParameters();
3373

    
3374
        DefaultFeatureStore cloned_store = null;
3375

    
3376
        try {
3377
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3378
                openStore(this.getProviderName(), dsp);
3379
            if (transforms != null) {
3380
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3381
                cloned_store.transforms.setStoreForClone(cloned_store);
3382
            }
3383
        } catch (Exception e) {
3384
            throw new CloneException(e);
3385
        }
3386
        return cloned_store;
3387

    
3388
    }
3389

    
3390
    @Override
3391
    public Feature getFeature(DynObject dynobject) {
3392
        if (dynobject instanceof DynObjectFeatureFacade){
3393
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
3394
            return f;
3395
        }
3396
        return null;
3397
    }
3398

    
3399
    @Override
3400
    public Iterator iterator() {
3401
        FeatureSet fset = null;
3402
        try {
3403
            fset  = this.getFeatureSet();
3404
            return fset.fastIterator();
3405
        } catch (DataException ex) {
3406
            throw new RuntimeException(ex);
3407
        } finally {
3408
            DisposeUtils.disposeQuietly(fset);
3409
        }
3410
    }
3411

    
3412
    @Override
3413
    public long size64() {
3414
        FeatureSet fset = null;
3415
        try {
3416
            fset  = this.getFeatureSet();
3417
            return fset.getSize();
3418
        } catch (DataException ex) {
3419
            throw new RuntimeException(ex);
3420
        } finally {
3421
            DisposeUtils.disposeQuietly(fset);
3422
        }
3423
    }
3424
   
3425
    @Override
3426
    public ExpressionBuilder createExpressionBuilder() {
3427
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3428
        return builder;
3429
    }
3430

    
3431
    @Override
3432
    public ExpressionBuilder createExpression() {
3433
        return createExpressionBuilder();
3434
    }
3435

    
3436
    public FeatureSet features() throws DataException {
3437
        // This is to avoid jython to create a property with this name
3438
        // to access method getFeatures.
3439
        return this.getFeatureSet();
3440
    }
3441

    
3442
    @Override
3443
    public DataStoreProviderFactory getProviderFactory() {
3444
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3445
        return factory;
3446
    }
3447

    
3448
    @Override
3449
    public void useCache(String providerName, DynObject parameters) throws DataException {
3450
        throw new UnsupportedOperationException();
3451
    }
3452

    
3453
    @Override
3454
    public boolean isBroken() {
3455
        return this.state.isBroken();
3456
    }
3457

    
3458
    @Override
3459
    public Throwable getBreakingsCause() {
3460
            return this.state.getBreakingsCause();
3461
    }
3462

    
3463
    @Override
3464
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3465
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3466
      if( !factory.supportNumericOID() ) {
3467
          return null;
3468
      }
3469
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3470
      return wrappedIndex;
3471
  }
3472

    
3473
    @Override
3474
    public FeatureReference getFeatureReference(String code) {
3475
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
3476
        return featureReference;
3477
    }
3478

    
3479
    @Override
3480
    public long getPendingChangesCount() {
3481
        if( this.featureManager==null ) {
3482
            return 0;
3483
        }
3484
        return this.featureManager.getPendingChangesCount();
3485
    }
3486

    
3487
    @Override
3488
    public ResourcesStorage getResourcesStorage() {
3489
        ResourcesStorage resourcesStorage;
3490
        try {
3491
            resourcesStorage = this.provider.getResourcesStorage();
3492
            if( resourcesStorage!=null ) {
3493
                return resourcesStorage;
3494
            }
3495
        } catch(Throwable th) {
3496
            
3497
        }
3498
        try {
3499
            DataServerExplorer explorer = this.getExplorer();
3500
            if( explorer==null ) {
3501
                return null;
3502
            }
3503
            resourcesStorage = explorer.getResourcesStorage(this);
3504
            explorer.dispose();
3505
            return resourcesStorage;
3506
        } catch (Exception ex) {
3507
            LOGGER.warn("Can't create resources storage",ex);
3508
            return null;
3509
        }
3510
    }
3511

    
3512
    @Override
3513
    public StoresRepository getStoresRepository() {
3514
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3515
        StoresRepository localRepository = this.provider.getStoresRepository();
3516
        if( localRepository==null ) {
3517
            return mainRepository;
3518
        }
3519
        StoresRepository repository = new BaseStoresRepository(this.getName());
3520
        repository.addRepository(localRepository);
3521
        repository.addRepository(mainRepository);
3522
        return repository;
3523
    }
3524

    
3525
    @Override
3526
    public Feature getSampleFeature() {
3527
            Feature sampleFeature;
3528
            try {
3529
                FeatureSelection theSelection = this.getFeatureSelection();
3530
                if( theSelection!=null && !theSelection.isEmpty() ) {
3531
                    sampleFeature = theSelection.first();
3532
                } else {
3533
                    sampleFeature = this.first();
3534
                }
3535
                if( sampleFeature==null ) {
3536
                    sampleFeature = this.createNewFeature();
3537
                }
3538
            } catch (DataException ex) {
3539
                return null;
3540
            }
3541
            return sampleFeature;
3542
    }
3543

    
3544
    @Override
3545
    public boolean supportReferences() {
3546
        try {
3547
            return this.getDefaultFeatureType().supportReferences();
3548
        } catch (Exception ex) {
3549
            return false;
3550
        }
3551
    }
3552

    
3553
    @Override
3554
    public boolean isTemporary() {
3555
        if( this.provider==null ) {
3556
            return true;
3557
        }
3558
        return this.provider.isTemporary();
3559
    }
3560
    
3561
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3562
        // FIXME this don't work for Store.fType.size() > 1
3563
        FeatureTypeManager manager = this.featureTypeManager;
3564
         if (manager==null) {
3565
             return null;
3566
         }
3567
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3568
         if (originalFeatureType==null) {
3569
             return null;
3570
         }
3571
         return originalFeatureType.getCopy();
3572
    }
3573

    
3574
    @Override
3575
    public Object getProperty(String name) {
3576
        if( this.propertiesSupportHelper==null ) {
3577
            return null;
3578
        }
3579
        return this.propertiesSupportHelper.getProperty(name);
3580
    }
3581

    
3582
    @Override
3583
    public void setProperty(String name, Object value) {
3584
        if( this.propertiesSupportHelper==null ) {
3585
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3586
        }
3587
        this.propertiesSupportHelper.setProperty(name,value);
3588
    }
3589

    
3590
    @Override
3591
    public Map<String, Object> getProperties() {
3592
        if( this.propertiesSupportHelper==null ) {
3593
            return Collections.EMPTY_MAP;
3594
        }
3595
        return this.propertiesSupportHelper.getProperties();
3596
    }
3597
    
3598
    
3599

    
3600

    
3601
}