Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-cvsgis1 / 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 @ 45267

History | View | Annotate | Download (115 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 org.gvsig.fmap.dal.feature.impl.editing.memory.SpatialManager;
28
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureTypeManager;
29
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureManager;
30

    
31
import java.util.ArrayList;
32
import java.util.Collection;
33
import java.util.Collections;
34
import java.util.HashMap;
35
import java.util.HashSet;
36
import java.util.Iterator;
37
import java.util.List;
38
import java.util.Map;
39
import java.util.Map.Entry;
40
import java.util.Set;
41
import javax.json.JsonObject;
42

    
43
import org.apache.commons.io.FilenameUtils;
44
import org.apache.commons.io.IOUtils;
45
import org.apache.commons.lang3.StringUtils;
46
import org.apache.commons.lang3.mutable.MutableObject;
47
import org.cresques.cts.IProjection;
48
import org.gvsig.expressionevaluator.Expression;
49
import org.gvsig.expressionevaluator.ExpressionBuilder;
50
import org.gvsig.expressionevaluator.ExpressionUtils;
51
import org.gvsig.expressionevaluator.GeometryExpressionUtils;
52
import org.gvsig.fmap.dal.BaseStoresRepository;
53

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

    
183
@SuppressWarnings("UseSpecificCatch")
184
public class DefaultFeatureStore extends AbstractDataStore implements
185
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
186

    
187
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
188

    
189
    private DataStoreParameters parameters = null;
190
    private FeatureSelection selection;
191
    private FeatureLocks locks;
192

    
193
    private DelegateWeakReferencingObservable delegateObservable =
194
        new DelegateWeakReferencingObservable(this);
195

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

    
205
    private FeatureType defaultFeatureType = null;
206
    private List<FeatureType> featureTypes = new ArrayList<>();
207

    
208
    private int mode = MODE_QUERY;
209
    private long versionOfUpdate = 0;
210
    private boolean hasStrongChanges = true;
211
    private boolean hasInserts = true;
212

    
213
    private DefaultDataManager dataManager = null;
214

    
215
    private FeatureStoreProvider provider = null;
216

    
217
    private DefaultFeatureIndexes indexes;
218

    
219
    private DefaultFeatureStoreTransforms transforms;
220

    
221
    /*friend*/ DelegatedDynObject metadata;
222

    
223
    private Set metadataChildren;
224

    
225
    private Long featureCount = null;
226

    
227
    private long temporalOid = 0;
228

    
229
    private FeatureCacheProvider cache;
230

    
231
    private StateInformation state;
232

    
233
    private FeatureStoreTimeSupport timeSupport;
234
    
235
    private PropertiesSupportHelper propertiesSupportHelper;
236

    
237
    private class StateInformation extends HashMap<Object, Object> {
238

    
239
        private static final long serialVersionUID = 4109026189635185666L;
240

    
241
        private boolean broken;
242
        private Throwable breakingsCause;
243

    
244
        @SuppressWarnings("OverridableMethodCallInConstructor")
245
        public StateInformation() {
246
            this.clear();
247
        }
248

    
249
        @Override
250
        public void clear() {
251
            this.broken = false;
252
            this.breakingsCause = null;
253
            super.clear();
254
        }
255

    
256
        public boolean isBroken() {
257
            return this.broken;
258
        }
259

    
260
        public void broken() {
261
            this.broken = true;
262
        }
263

    
264
        public Throwable getBreakingsCause() {
265
            return this.breakingsCause;
266
        }
267

    
268
        public void setBreakingsCause(Throwable cause) {
269
            if( this.breakingsCause==null ) {
270
                this.breakingsCause = cause;
271
            }
272
            this.broken = true;
273
        }
274
    }
275

    
276

    
277

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

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

    
296
    @Override
297
    public void intialize(DataManager dataManager,
298
        DataStoreParameters parameters) throws InitializeException {
299

    
300
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
301

    
302
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
303
            FeatureStore.METADATA_DEFINITION_NAME,
304
            MetadataManager.METADATA_NAMESPACE
305
        );
306

    
307
        this.dataManager = (DefaultDataManager) dataManager;
308

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

    
317
    }
318

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

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

    
355
    public int getMode() {
356
        return this.mode;
357
    }
358

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
575
    @Override
576
    public FeatureSelection createDefaultFeatureSelection()
577
        throws DataException {
578
        return new DefaultFeatureSelection(this);
579
    }
580

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

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

    
626
        }
627

    
628
        if (evaluatedAttr.isEmpty()) {
629
            evaluatedAttr = null;
630
        }
631

    
632
        state.set("evaluatedAttributes", evaluatedAttr);
633
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
634

    
635
    }
636

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

    
675
    private void load(StateInformation state) {
676
        this.featureTypes = new ArrayList();
677
        this.defaultFeatureType = null;
678
        this.featureCount = null;
679

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

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

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

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

    
748
                    }
749

    
750
            }
751
        } catch(Throwable th) {
752
            state.setBreakingsCause(th);
753
        }
754

    
755

    
756
        try {
757
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
758
            FeatureType ftype;
759

    
760
            if (defaultFeatureType == null ||
761
                    defaultFeatureType.getId() == null ||
762
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
763

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

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

    
788
    public DataStoreProviderServices getStoreProviderServices() {
789
        return this;
790
    }
791

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

    
802
            definition.addDynFieldObject("parameters")
803
                .setClassOfValue(DynObject.class).setMandatory(true)
804
                .setPersistent(true);
805

    
806
            definition.addDynFieldObject("selection")
807
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
808
                .setPersistent(true);
809

    
810
            definition.addDynFieldObject("transforms")
811
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
812
                .setMandatory(true).setPersistent(true);
813

    
814
            definition.addDynFieldMap("evaluatedAttributes")
815
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
816
                .setMandatory(false).setPersistent(true);
817

    
818
            definition.addDynFieldString("defaultFeatureTypeId")
819
                .setMandatory(true).setPersistent(true);
820
        }
821
    }
822

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

    
833
    //
834
    // ====================================================================
835
    // Gestion de la seleccion
836
    //
837

    
838
    @Override
839
    public void setSelection(DataSet selection) throws DataException {
840
        this.setSelection((FeatureSet) selection);
841
    }
842

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

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

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

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

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

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

    
912
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
913
    }
914

    
915
    @Override
916
    public FeatureSelection createFeatureSelection() throws DataException {
917
        return this.provider.createFeatureSelection();
918
    }
919

    
920
    @Override
921
    public FeatureSelection getFeatureSelection() throws DataException {
922
        if (selection == null) {
923
            this.selection = createFeatureSelection();
924
            this.selection.addObserver(this);
925
        }
926
        return selection;
927
    }
928

    
929
    //
930
    // ====================================================================
931
    // Gestion de notificaciones
932
    //
933

    
934
    @Override
935
    public FeatureStoreNotification notifyChange(FeatureStoreNotification storeNotification) {
936
        if (delegateObservable != null) {
937
          try {
938
              delegateObservable.notifyObservers(storeNotification);
939
          } catch (Throwable ex) {
940
              LOGGER.warn("Problems notifying changes in the store '"+this.getName()+" ("+storeNotification.getType()+").",ex);
941
          }
942
        }
943
        return storeNotification;
944
    }
945

    
946
    @Override
947
    public FeatureStoreNotification notifyChange(String notification) {
948
      return notifyChange(new DefaultFeatureStoreNotification(this, notification));
949
    }
950
    
951
    public FeatureStoreNotification notifyChange(String notification,
952
      Iterator<FeatureReference> deleteds, 
953
      Iterator<Feature> inserteds, 
954
      Iterator<Feature> updateds, 
955
      Iterator<FeatureTypeChanged> featureTypesChanged, 
956
      boolean isSelectionCompromised) {
957
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
958
            deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised));
959
    }
960

    
961
    @Override
962
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
963
        Feature f = null;
964
        if( data !=null ) {
965
          try {
966
              f = createFeature(data);
967
          } catch (Throwable ex) {
968
              LOGGER.warn("Problems creating a feature to notifying changes in the store '"+this.getName()+" ("+notification+").",ex);
969
          }
970
        }
971
        return notifyChange(notification, f);
972
    }
973

    
974
    public FeatureStoreNotification notifyChange(String notification, Feature feature) {
975
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
976
            feature));
977
    }
978

    
979
    public FeatureStoreNotification notifyChange(String notification, Command command) {
980
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
981
            command));
982
    }
983

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

    
989
    @Override
990
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
991
        return notifyChange(new DefaultFeatureStoreNotification(this,
992
            DataStoreNotification.RESOURCE_CHANGED));
993
    }
994

    
995
    //
996
    // ====================================================================
997
    // Gestion de bloqueos
998
    //
999

    
1000
    @Override
1001
    public boolean isLocksSupported() {
1002
        return this.provider.isLocksSupported();
1003
    }
1004

    
1005
    @Override
1006
    public FeatureLocks getLocks() throws DataException {
1007
        if (!this.provider.isLocksSupported()) {
1008
            LOGGER.warn("Locks not supported");
1009
            return null;
1010
        }
1011
        if (locks == null) {
1012
            this.locks = this.provider.createFeatureLocks();
1013
        }
1014
        return locks;
1015
    }
1016

    
1017
    //
1018
    // ====================================================================
1019
    // Interface Observable
1020
    //
1021

    
1022
    @Override
1023
    public void disableNotifications() {
1024
        this.delegateObservable.disableNotifications();
1025

    
1026
    }
1027

    
1028
    @Override
1029
    public void enableNotifications() {
1030
        this.delegateObservable.enableNotifications();
1031
    }
1032

    
1033
    @Override
1034
    public void beginComplexNotification() {
1035
        this.delegateObservable.beginComplexNotification();
1036

    
1037
    }
1038

    
1039
    @Override
1040
    public void endComplexNotification() {
1041
        this.delegateObservable.endComplexNotification();
1042

    
1043
    }
1044

    
1045
    @Override
1046
    public void addObserver(Observer observer) {
1047
        if (delegateObservable != null) {
1048
            this.delegateObservable.addObserver(observer);
1049
        }
1050
    }
1051

    
1052
    @Override
1053
    public void deleteObserver(Observer observer) {
1054
        if (delegateObservable != null) {
1055
            this.delegateObservable.deleteObserver(observer);
1056
        }
1057
    }
1058

    
1059
    @Override
1060
    public void deleteObservers() {
1061
        this.delegateObservable.deleteObservers();
1062

    
1063
    }
1064

    
1065
    //
1066
    // ====================================================================
1067
    // Interface Observer
1068
    //
1069
    // Usado para observar:
1070
    // - su seleccion
1071
    // - sus bloqueos
1072
    // - sus recursos
1073
    //
1074

    
1075
    @Override
1076
    public void update(Observable observable, Object notification) {
1077
        if (observable instanceof FeatureSet) {
1078
            if (observable == this.selection) {
1079
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1080
            } else if (observable == this.locks) {
1081
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1082
            }
1083

    
1084
        } else if (observable instanceof FeatureStoreProvider) {
1085
            if (observable == this.provider) {
1086

    
1087
            }
1088
        } else if (observable instanceof FeatureReferenceSelection) {
1089
            if(notification instanceof String){
1090
                    this.notifyChange((String)notification);
1091
            }
1092
        }
1093
    }
1094

    
1095
    //
1096
    // ====================================================================
1097
    // Edicion
1098
    //
1099

    
1100
    private void newVersionOfUpdate() {
1101
        this.versionOfUpdate++;
1102
    }
1103

    
1104
    private long currentVersionOfUpdate() {
1105
        return this.versionOfUpdate;
1106
    }
1107

    
1108
    private void checkInEditingMode() throws NeedEditingModeException {
1109
        if (mode != MODE_FULLEDIT) {
1110
            throw new NeedEditingModeException(this.getName());
1111
        }
1112
    }
1113

    
1114
    private void checkNotInAppendMode() throws IllegalStateException {
1115
        if (mode == MODE_APPEND) {
1116
                        throw new IllegalStateException("Error: store "
1117
                                        + this.getFullName() + " is in append mode");
1118
        }
1119
    }
1120

    
1121
    private void checkIsOwnFeature(Feature feature)
1122
        throws IllegalFeatureException {
1123
        if (((DefaultFeature) feature).getStore() != this) {
1124
            throw new IllegalFeatureException(this.getName());
1125
        }
1126
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1127
        // fixFeatureType((DefaultFeatureType) feature.getType());
1128
    }
1129

    
1130
    private void exitEditingMode() {
1131
        if (commands != null) {
1132
            commands.clear();
1133
            commands = null;
1134
        }
1135

    
1136
        if (featureTypeManager != null) {
1137
            featureTypeManager.dispose();
1138
            featureTypeManager = null;
1139

    
1140
        }
1141

    
1142
        // TODO implementar un dispose para estos dos
1143
        featureManager = null;
1144
        spatialManager = null;
1145

    
1146
        featureCount = null;
1147

    
1148
        mode = MODE_QUERY;
1149
        hasStrongChanges = true; // Lo deja a true por si las moscas
1150
        hasInserts = true;
1151
    }
1152

    
1153
    @Override
1154
    synchronized public void edit() throws DataException {
1155
        edit(MODE_FULLEDIT);
1156
    }
1157

    
1158
    @Override
1159
    synchronized public void edit(int mode) throws DataException {
1160
        LOGGER.debug("Starting editing in mode: {}", mode);
1161
        try {
1162
            if (this.mode != MODE_QUERY) {
1163
                throw new AlreadyEditingException(this.getName());
1164
            }
1165
            if (!this.provider.supportsAppendMode()) {
1166
                mode = MODE_FULLEDIT;
1167
            }
1168
            switch (mode) {
1169
            case MODE_QUERY:
1170
                throw new IllegalStateException(this.getName());
1171

    
1172
            case MODE_FULLEDIT:
1173
                if (!this.transforms.isEmpty()) {
1174
                    throw new IllegalStateException(this.getName());
1175
                }
1176
                if( notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING).isCanceled() ) {
1177
                  return;
1178
                }
1179
                invalidateIndexes();
1180
                featureManager = new FeatureManager();
1181
                featureTypeManager = new FeatureTypeManager(this);
1182
                spatialManager = new SpatialManager(this, provider.getEnvelope());
1183

    
1184
                commands = new DefaultFeatureCommandsStack(
1185
                        this, featureManager,
1186
                        spatialManager, featureTypeManager);
1187
                this.mode = MODE_FULLEDIT;
1188
                hasStrongChanges = false;
1189
                hasInserts = false;
1190
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1191
                break;
1192
            case MODE_APPEND:
1193
                if (!this.transforms.isEmpty()) {
1194
                    throw new IllegalStateException(this.getName());
1195
                }
1196
                if( notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING).isCanceled() ) {
1197
                  return;
1198
                }
1199
                invalidateIndexes();
1200
                this.provider.beginAppend();
1201
                this.mode = MODE_APPEND;
1202
                hasInserts = false;
1203
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1204
                break;
1205
            }
1206
        } catch (Exception e) {
1207
            throw new StoreEditException(e, this.getName());
1208
        }
1209
    }
1210

    
1211
    private void invalidateIndexes() {
1212
        setIndexesValidStatus(false);
1213
    }
1214

    
1215
    private void setIndexesValidStatus(boolean valid) {
1216
        FeatureIndexes theIndexes = getIndexes();
1217
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1218
            ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1219
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1220
            FeatureIndex index = (FeatureIndex) iterator.next();
1221
            if (index instanceof FeatureIndexProviderServices) {
1222
                FeatureIndexProviderServices indexServices =
1223
                    (FeatureIndexProviderServices) index;
1224
                indexServices.setValid(valid);
1225
            }
1226
        }
1227
    }
1228

    
1229
    private void updateIndexes() throws FeatureIndexException {
1230
        FeatureIndexes theIndexes = getIndexes();
1231
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1232
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1233
            FeatureIndex index = (FeatureIndex) iterator.next();
1234
            if (index instanceof FeatureIndexProviderServices) {
1235
                FeatureIndexProviderServices indexServices =
1236
                    (FeatureIndexProviderServices) index;
1237
                indexServices.fill(true, null);
1238
            }
1239
        }
1240
    }
1241

    
1242
    private void waitForIndexes() {
1243
        FeatureIndexes theIndexes = getIndexes();
1244
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1245
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1246
            FeatureIndex index = (FeatureIndex) iterator.next();
1247
            if (index instanceof FeatureIndexProviderServices) {
1248
                FeatureIndexProviderServices indexServices =
1249
                    (FeatureIndexProviderServices) index;
1250
                indexServices.waitForIndex();
1251
            }
1252
        }
1253
    }
1254

    
1255
    private void disposeIndexes() {
1256
        FeatureIndexes theIndexes = getIndexes();
1257
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1258
        if( theIndexes==null ) {
1259
            return;
1260
        }
1261
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1262
            FeatureIndex index = (FeatureIndex) iterator.next();
1263
            if (index instanceof FeatureIndexProviderServices) {
1264
                FeatureIndexProviderServices indexServices =
1265
                    (FeatureIndexProviderServices) index;
1266
                indexServices.dispose();
1267
            }
1268
        }
1269
    }
1270

    
1271
    @Override
1272
    public boolean isEditing() {
1273
        return mode == MODE_FULLEDIT;
1274
    }
1275

    
1276
    @Override
1277
    public boolean isAppending() {
1278
        return mode == MODE_APPEND;
1279
    }
1280

    
1281
    @Override
1282
    synchronized public void update(EditableFeatureType type)
1283
        throws DataException {
1284
        try {
1285
            if (type == null) {
1286
                throw new NullFeatureTypeException(getName());
1287
            }
1288
            if (mode == MODE_QUERY && type.hasOnlyMetadataChanges(this.defaultFeatureType)) {
1289
                if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled() ) {
1290
                  return;
1291
                }
1292
                FeatureType theType = type.getNotEditableCopy();
1293
                if( defaultFeatureType.getId().equals(theType.getId()) ) {
1294
                    defaultFeatureType = theType;
1295
                }
1296
                List newtypes = new ArrayList();
1297
                for (FeatureType featureType : this.featureTypes) {
1298
                    if( featureType.getId().equals(theType.getId()) ) {
1299
                        newtypes.add(theType);
1300
                    } else {
1301
                        newtypes.add(featureType);
1302
                    }                    
1303
                }
1304
                this.featureTypes = newtypes;
1305
                saveDALFile();
1306
                notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1307
                return ;
1308
            }
1309
            boolean typehasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1310
            if (typehasStrongChanges) {
1311
                checkInEditingMode();
1312
            }  else if(this.isAppending()) {
1313
                throw new NeedEditingModeException(this.getName());
1314
            }
1315
            // FIXME: Comprobar que es un featureType aceptable.
1316
            if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled() ) {
1317
              return;
1318
            }
1319
            newVersionOfUpdate();
1320
            
1321
            FeatureType oldt = type.getSource().getCopy();
1322
            FeatureType newt = type.getCopy();
1323
            commands.update(newt, oldt);
1324
            if (typehasStrongChanges) { 
1325
                hasStrongChanges = true;
1326
            }
1327
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1328
        } catch (Exception e) {
1329
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1330
        }
1331
    }
1332

    
1333
    @Override
1334
    public void delete(Feature feature) throws DataException {
1335
        this.commands.delete(feature);
1336
    }
1337
    
1338
    @Override
1339
    public void delete(String filter) {
1340
        if( StringUtils.isBlank(filter) ) {
1341
            return;
1342
        }
1343
        this.delete(ExpressionUtils.createExpression(filter));
1344
    }
1345
    
1346
    @Override
1347
    public void delete(Expression filter) {
1348
        // TODO: Optimizar pasandolo directamente al proveedor si no estamos en edicion y lo soporta.
1349
        if( filter == null ) {
1350
            return;
1351
        }
1352
        boolean pendingFinishEditing = false;
1353
        DisposableFeatureSetIterable features = null;
1354
        try {
1355
            if( !this.isEditing() ) {
1356
                pendingFinishEditing = true;
1357
                this.edit();
1358
            }
1359
            FeatureSet fset = this.getFeatureSet(filter);
1360
            features = fset.iterable(); 
1361
            for (Feature f : features) {
1362
                fset.delete(f);
1363
            }
1364
        } catch(DataException ex) {
1365
            throw new DataRuntimeException(ex.getFormatString(), ex.getMessageKey(), ex.getCode()) {};
1366
        } catch(Exception ex) {
1367
            throw new RuntimeException("Can't delete features ("+filter.getPhrase()+").", ex);
1368
        } finally {
1369
            if( pendingFinishEditing ) {
1370
                this.finishEditingQuietly();
1371
            }
1372
            DisposeUtils.disposeQuietly(features);
1373
        }
1374
    }
1375
    
1376
    synchronized public void doDelete(Feature feature) throws DataException {
1377
        try {
1378
            checkInEditingMode();
1379
            checkIsOwnFeature(feature);
1380
            if (feature instanceof EditableFeature) {
1381
                throw new StoreDeleteEditableFeatureException(getName());
1382
            }
1383
            if( notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled() ) {
1384
              return;
1385
            }
1386

    
1387
            //Update the featureManager and the spatialManager
1388
            featureManager.delete(feature.getReference());
1389
            spatialManager.deleteFeature(feature);
1390

    
1391
            newVersionOfUpdate();
1392
            hasStrongChanges = true;
1393
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1394
        } catch (Exception e) {
1395
            throw new StoreDeleteFeatureException(e, this.getName());
1396
        }
1397
    }
1398

    
1399
    public synchronized void insert(FeatureSet set) throws DataException {
1400
        switch (mode) {
1401
        case MODE_QUERY:
1402
            throw new NeedEditingModeException(this.getName());
1403

    
1404
        case MODE_APPEND:
1405
        case MODE_FULLEDIT:
1406
            break;
1407
        }
1408
        try {
1409
            set.accept((Object obj) -> {
1410
                EditableFeature ef = createNewFeature((Feature) obj);
1411
                insert(ef);
1412
            });
1413
        } catch (BaseException ex) {
1414
            throw new StoreInsertFeatureException(ex, this.getName());
1415
        }
1416
    }
1417
    
1418
    private static EditableFeature lastChangedFeature = null;
1419

    
1420
    @Override
1421
    public synchronized void insert(EditableFeature feature)
1422
        throws DataException {
1423
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1424
        try {
1425
            switch (mode) {
1426
            case MODE_QUERY:
1427
                throw new NeedEditingModeException(this.getName());
1428

    
1429
            case MODE_APPEND:
1430
                checkIsOwnFeature(feature);
1431
                if (feature.getSource() != null) {
1432
                    throw new NoNewFeatureInsertException(this.getName());
1433
                }
1434
                if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1435
                  return;
1436
                }
1437
                this.featureCount = null;
1438
                feature.validate(Feature.UPDATE);
1439
                provider.append(((DefaultEditableFeature) feature).getData());
1440
                hasStrongChanges = true;
1441
                hasInserts = true;
1442
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1443
                break;
1444

    
1445
            case MODE_FULLEDIT:
1446
                if (feature.getSource() != null) {
1447
                    throw new NoNewFeatureInsertException(this.getName());
1448
                }
1449
                feature.validate(Feature.UPDATE);
1450
                commands.insert(feature);
1451
            }
1452
        } catch (Exception e) {
1453
            throw new StoreInsertFeatureException(e, this.getName());
1454
        }
1455
    }
1456

    
1457
    synchronized public void doInsert(EditableFeature feature)
1458
        throws DataException {
1459
        checkIsOwnFeature(feature);
1460

    
1461
        waitForIndexes();
1462

    
1463
        if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1464
          return;
1465
        }
1466
        newVersionOfUpdate();
1467
        if ((lastChangedFeature == null)
1468
            || (lastChangedFeature.getSource() != feature.getSource())) {
1469
            lastChangedFeature = feature;
1470
            feature.validate(Feature.UPDATE);
1471
            lastChangedFeature = null;
1472
        }
1473
        //Update the featureManager and the spatialManager
1474
        ((DefaultEditableFeature) feature).setInserted(true);
1475
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1476

    
1477

    
1478
        featureManager.add(newFeature);
1479
        spatialManager.insertFeature(newFeature);
1480

    
1481
        hasStrongChanges = true;
1482
        hasInserts = true;
1483
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1484
    }
1485

    
1486
    @Override
1487
    public void update(EditableFeature feature)
1488
    throws DataException {
1489
        if ((feature).getSource() == null) {
1490
            insert(feature);
1491
            return;
1492
        }
1493
        commands.update(feature, feature.getSource());
1494
    }
1495

    
1496
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1497
        throws DataException {
1498
        try {
1499
            checkInEditingMode();
1500
            checkIsOwnFeature(feature);
1501
            if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled() ) {
1502
              return;
1503
            }
1504
            newVersionOfUpdate();
1505
            if ((lastChangedFeature == null)
1506
                || (lastChangedFeature.getSource() != feature.getSource())) {
1507
                lastChangedFeature = feature;
1508
                feature.validate(Feature.UPDATE);
1509
                lastChangedFeature = null;
1510
            }
1511

    
1512
            //Update the featureManager and the spatialManager
1513
            Feature newf = feature.getNotEditableCopy();
1514
            featureManager.update(newf, oldFeature);
1515
            spatialManager.updateFeature(newf, oldFeature);
1516

    
1517
            hasStrongChanges = true;
1518
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1519
        } catch (Exception e) {
1520
            throw new StoreUpdateFeatureException(e, this.getName());
1521
        }
1522
    }
1523

    
1524
    @Override
1525
    synchronized public void redo() throws RedoException {
1526
        Command redo = commands.getNextRedoCommand();
1527
        try {
1528
            checkInEditingMode();
1529
        } catch (NeedEditingModeException ex) {
1530
            throw new RedoException(redo, ex);
1531
        }
1532
        if( notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled() ) {
1533
          return;
1534
        }
1535
        newVersionOfUpdate();
1536
        commands.redo();
1537
        hasStrongChanges = true;
1538
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1539
    }
1540

    
1541
    @Override
1542
    synchronized public void undo() throws UndoException {
1543
        Command undo = commands.getNextUndoCommand();
1544
        try {
1545
            checkInEditingMode();
1546
        } catch (NeedEditingModeException ex) {
1547
            throw new UndoException(undo, ex);
1548
        }
1549
        if( notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled() ) {
1550
          return;
1551
        }
1552
        newVersionOfUpdate();
1553
        commands.undo();
1554
        hasStrongChanges = true;
1555
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1556
    }
1557

    
1558
    @Override
1559
    public List getRedoInfos() {
1560
        if (isEditing() && (commands != null)) {
1561
            return commands.getRedoInfos();
1562
        } else {
1563
            return null;
1564
        }
1565
    }
1566

    
1567
    @Override
1568
    public List getUndoInfos() {
1569
        if (isEditing() && (commands != null)) {
1570
            return commands.getUndoInfos();
1571
        } else {
1572
            return null;
1573
        }
1574
    }
1575

    
1576
    public synchronized FeatureCommandsStack getCommandsStack()
1577
        throws DataException {
1578
        checkInEditingMode();
1579
        return commands;
1580
    }
1581

    
1582
    @Override
1583
    public boolean cancelEditingQuietly() {
1584
        try {
1585
            this.cancelEditing();
1586
            return true;
1587
        } catch(Exception ex) {
1588
            LOGGER.debug("Can't cancel editing", ex);
1589
            return false;
1590
        }
1591
    }
1592
    
1593
    @Override
1594
    synchronized public void cancelEditing() throws DataException {
1595
        if( spatialManager!=null ) {
1596
            spatialManager.cancelModifies();
1597
        }
1598
        try {
1599
            switch (mode) {
1600
            case MODE_QUERY:
1601
                throw new NeedEditingModeException(this.getName());
1602

    
1603
            case MODE_APPEND:
1604
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1605
                  return;
1606
                }
1607
                provider.abortAppend();
1608
                exitEditingMode();
1609
                ((FeatureSelection) this.getSelection()).deselectAll();
1610
                updateIndexes();
1611
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1612

    
1613
            case MODE_FULLEDIT:
1614
                boolean clearSelection = this.hasStrongChanges;
1615
                if (this.selection instanceof FeatureReferenceSelection) {
1616
                    clearSelection = this.hasInserts;
1617
                }
1618
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1619
                  return;
1620
                }
1621
                exitEditingMode();
1622
                if (clearSelection) {
1623
                    ((FeatureSelection) this.getSelection()).deselectAll();
1624
                }
1625
                updateIndexes();
1626
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1627
            }
1628
        } catch (Exception e) {
1629
            throw new StoreCancelEditingException(e, this.getName());
1630
        }
1631
    }
1632

    
1633
    @Override
1634
    public boolean finishEditingQuietly() {
1635
        try {
1636
            this.finishEditing();
1637
            return true;
1638
        } catch(Exception ex) {
1639
            LOGGER.debug("Can't finish editing", ex);
1640
            return false;
1641
        }
1642
    }
1643
    
1644
    @Override
1645
    synchronized public void finishEditing() throws DataException {
1646
        LOGGER.debug("finish editing of mode: {}", mode);
1647
        try {
1648

    
1649
            /*
1650
             * Selection needs to be cleared when editing stops
1651
             * to prevent conflicts with selection remaining from
1652
             * editing mode.
1653
             */
1654
//            ((FeatureSelection) this.getSelection()).deselectAll();
1655
            Map<String,List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1656
            switch (mode) {
1657
            case MODE_QUERY:
1658
                throw new NeedEditingModeException(this.getName());
1659

    
1660
            case MODE_APPEND:
1661
                if( selection!=null ) {
1662
                    selection = null;
1663
                }
1664
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled() ) {
1665
                  return;
1666
                }
1667
                saveDALFile();
1668
                provider.endAppend();
1669
                exitEditingMode();
1670
                this.updateComputedFields(computedFields);
1671
                loadDALFile();
1672
                updateIndexes();
1673
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1674
                break;
1675

    
1676
            case MODE_FULLEDIT:
1677
                if (hasStrongChanges && !this.allowWrite()) {
1678
                    throw new WriteNotAllowedException(getName());
1679
                }
1680
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, 
1681
                        featureManager.getDeleted(),
1682
                        featureManager.getInsertedFeatures(),
1683
                        featureManager.getUpdatedFeatures(),
1684
                        featureTypeManager.getFeatureTypesChanged().iterator(),
1685
                        featureManager.isSelectionCompromised()).isCanceled() ) {
1686
                  return;
1687
                }
1688
                saveDALFile();
1689
                if(featureManager.isSelectionCompromised() && selection!=null ) {
1690
                    selection = null;
1691
                }
1692
                if (hasStrongChanges) {
1693
                    validateFeatures(Feature.FINISH_EDITING);
1694

    
1695
                    /*
1696
                     * This will throw a PerformEditingExceptionif the provider
1697
                     * does not accept the changes (for example, an invalid field name)
1698
                     */
1699
                    provider.performChanges(featureManager.getDeleted(),
1700
                        featureManager.getInserted(),
1701
                        featureManager.getUpdated(),
1702
                        removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1703
                    
1704
                }  
1705
                this.updateComputedFields(computedFields);
1706
                exitEditingMode();
1707
                loadDALFile();
1708
                updateIndexes();
1709
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1710
                break;
1711
            }
1712
        } catch (PerformEditingException pee) {
1713
            throw new WriteException(provider.getSourceId().toString(), pee);
1714
        } catch (Exception e) {
1715
            throw new FinishEditingException(e);
1716
        }
1717
    }
1718
    private Map<String,List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
1719
        Map<String,List<FeatureAttributeDescriptor>> r = new HashMap<>();
1720
        
1721
        List<FeatureType> theTypes = new ArrayList<>();
1722
        theTypes.addAll(this.getFeatureTypes());
1723
        theTypes.add(this.getDefaultFeatureType());
1724
        for( int n=0; n<theTypes.size(); n++ ) {
1725
            FeatureType type = theTypes.get(n);
1726
                for (FeatureAttributeDescriptor attrdesc : type) {
1727
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
1728
                    if( emulator!= null) {
1729
                        List<FeatureAttributeDescriptor> l = r.get(type.getId());
1730
                        if (l==null) {
1731
                            l = new ArrayList<>();
1732
                            r.put(type.getId(), l);
1733
                        }
1734
                        l.add(attrdesc);
1735
                    }
1736
            }
1737
        }
1738
        return r;
1739
    }
1740
    private void updateComputedFields(Map<String,List<FeatureAttributeDescriptor>> computedFields) throws DataException {
1741

    
1742
        List<FeatureType> theTypes = new ArrayList<>();
1743
        theTypes.addAll(this.getFeatureTypes());
1744
        theTypes.add(this.getDefaultFeatureType());
1745
        for( int n=0; n<theTypes.size(); n++ ) {
1746
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1747
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1748
            if(x!=null && !x.isEmpty()) {
1749
                for (FeatureAttributeDescriptor attrdesc : x) {
1750
                    if (type.get(attrdesc.getName())==null) {
1751
                        type.add(attrdesc);
1752
                    }
1753
                }
1754
            }
1755
        }
1756
        
1757
    }
1758
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
1759
        // FIXME: Falta por implementar
1760
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
1761
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
1762
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
1763
//                if (attributeDescriptor.isComputed()) {
1764
//                    target.remove(attributeDescriptor.getName());
1765
//                }
1766
//            }
1767
//        }
1768
        return ftypes;
1769
    }
1770
    
1771

    
1772
    private void saveDALFile() {       
1773
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1774
        try {
1775
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1776
            if( resourcesStorage == null || resourcesStorage.isReadOnly() ) {
1777
                return;
1778
            }
1779
            resource = resourcesStorage.getResource("dal");
1780
            if( resource == null || resource.isReadOnly() ) {
1781
                return;
1782
            }
1783
            DALFile dalFile = DALFile.getDALFile();
1784
            dalFile.setStore(this);
1785
            if( !dalFile.isEmpty() ) {
1786
                dalFile.write(resource);
1787
            }
1788
        } catch (Throwable ex) {
1789
            LOGGER.warn("Can't save DAL resource", ex);
1790
        } finally {
1791
            IOUtils.closeQuietly(resource);
1792
        }
1793
    }
1794
    
1795
    private void loadDALFile() {
1796
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1797
        try {
1798
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1799
            if( resourcesStorage == null ) {
1800
                return;
1801
            }
1802
            resource = resourcesStorage.getResource("dal");
1803
            if( resource == null || !resource.exists() ) {
1804
                return;
1805
            }
1806
            DALFile dalFile = DALFile.getDALFile(resource);
1807
            if( !dalFile.isEmpty() ) {
1808
                dalFile.updateStore(this);
1809
            }
1810
        } catch (Throwable ex) {
1811
            LOGGER.warn("Can't load DAL resource", ex);
1812
        } finally {
1813
            IOUtils.closeQuietly(resource);
1814
        }
1815
    }
1816
    
1817
    /**
1818
     * Save changes in the provider without leaving the edit mode.
1819
     * Do not call observers to communicate a change of ediding mode.
1820
     * The operation's history is eliminated to prevent inconsistencies
1821
     * in the data.
1822
     *
1823
     * @throws DataException
1824
     */
1825
    @Override
1826
    synchronized public void commitChanges() throws DataException {
1827
      LOGGER.debug("commitChanges of mode: {}", mode);
1828
      if( !canCommitChanges() ) {
1829
              throw new WriteNotAllowedException(getName());
1830
      }
1831
      try {
1832
        switch (mode) {
1833
        case MODE_QUERY:
1834
          throw new NeedEditingModeException(this.getName());
1835

    
1836
        case MODE_APPEND:
1837
          this.provider.endAppend();
1838
          exitEditingMode();
1839
          invalidateIndexes();
1840
          this.provider.beginAppend();
1841
          hasInserts = false;
1842
          break;
1843

    
1844
        case MODE_FULLEDIT:
1845
          if (hasStrongChanges && !this.allowWrite()) {
1846
            throw new WriteNotAllowedException(getName());
1847
          }
1848
          if (hasStrongChanges) {
1849
            validateFeatures(Feature.FINISH_EDITING);
1850
            provider.performChanges(featureManager.getDeleted(),
1851
              featureManager.getInserted(),
1852
              featureManager.getUpdated(),
1853
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1854
          }
1855
          invalidateIndexes();
1856
          featureManager = new FeatureManager();
1857
          featureTypeManager = new FeatureTypeManager(this);
1858
          spatialManager = new SpatialManager(this, provider.getEnvelope());
1859

    
1860
          commands =
1861
            new DefaultFeatureCommandsStack(this, featureManager,
1862
              spatialManager, featureTypeManager);
1863
          featureCount = null;
1864
          hasStrongChanges = false;
1865
          hasInserts = false;
1866
          break;
1867
        }
1868
      } catch (Exception e) {
1869
        throw new FinishEditingException(e);
1870
      }
1871
    }
1872

    
1873
    @Override
1874
    synchronized public boolean canCommitChanges() throws DataException {
1875
        if ( !this.allowWrite()) {
1876
                return false;
1877
        }
1878
            switch (mode) {
1879
            default:
1880
        case MODE_QUERY:
1881
                return false;
1882

    
1883
        case MODE_APPEND:
1884
                return true;
1885

    
1886
        case MODE_FULLEDIT:
1887
            List types = this.getFeatureTypes();
1888
            for( int i=0; i<types.size(); i++ ) {
1889
                    Object type = types.get(i);
1890
                    if( type instanceof DefaultEditableFeatureType ) {
1891
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1892
                                    return false;
1893
                            }
1894
                    }
1895
            }
1896
            return true;
1897
            }
1898
    }
1899

    
1900
    @Override
1901
    public void beginEditingGroup(String description)
1902
        throws NeedEditingModeException {
1903
        checkInEditingMode();
1904
        commands.startComplex(description);
1905
    }
1906

    
1907
    @Override
1908
    public void endEditingGroup() throws NeedEditingModeException {
1909
        checkInEditingMode();
1910
        commands.endComplex();
1911
    }
1912

    
1913
    @Override
1914
    public boolean isAppendModeSupported() {
1915
        return this.provider.supportsAppendMode();
1916
    }
1917

    
1918
    @Override
1919
    public void export(DataServerExplorer explorer, String provider,
1920
        NewFeatureStoreParameters params) throws DataException {
1921

    
1922
        if (this.getFeatureTypes().size() != 1) {
1923
            throw new NotYetImplemented(
1924
                "export whith more than one type not yet implemented");
1925
        }
1926
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1927
        FeatureStore target = null;
1928
        FeatureSet features = null;
1929
        DisposableIterator iterator = null;
1930
        try {
1931
            FeatureType type = this.getDefaultFeatureType();
1932
            if ((params.getDefaultFeatureType() == null)
1933
                || (params.getDefaultFeatureType().size() == 0)) {
1934
                params.setDefaultFeatureType(type.getEditable());
1935

    
1936
            }
1937
            explorer.add(provider, params, true);
1938

    
1939
            DataManager manager = DALLocator.getDataManager();
1940
            target = (FeatureStore) manager.openStore(provider, params);
1941
            FeatureType targetType = target.getDefaultFeatureType();
1942

    
1943
            target.edit(MODE_APPEND);
1944
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
1945
            if (featureSelection.getSize() > 0) {
1946
                features = this.getFeatureSelection();
1947
            } else {
1948
                if ((pkattrs != null) && (pkattrs.length > 0)) {
1949
                    FeatureQuery query = createFeatureQuery();
1950
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
1951
                        query.getOrder().add(pkattr.getName(), true);
1952
                    }
1953
                    features = this.getFeatureSet(query);
1954
                } else {
1955
                    features = this.getFeatureSet();
1956
                }
1957
            }
1958
            iterator = features.fastIterator();
1959
            while (iterator.hasNext()) {
1960
                DefaultFeature feature = (DefaultFeature) iterator.next();
1961
                target.insert(target.createNewFeature(targetType, feature));
1962
            }
1963
            target.finishEditing();
1964
            target.dispose();
1965
        } catch (Exception e) {
1966
            throw new DataExportException(e, params.toString());
1967
        } finally {
1968
            dispose(iterator);
1969
            dispose(features);
1970
            dispose(target);
1971
        }
1972
    }
1973

    
1974
    public void copyTo(final FeatureStore target) {
1975
        boolean finishEditingAtEnd = false;
1976
        try {
1977
            if( !target.isEditing() && !target.isAppending() ) {
1978
                finishEditingAtEnd = true;
1979
                target.edit(MODE_APPEND);
1980
            }
1981
            this.accept(new Visitor() {
1982
                @Override
1983
                public void visit(Object obj) throws VisitCanceledException, BaseException {
1984
                    Feature f_src = (Feature) obj;
1985
                    EditableFeature f_dst = target.createNewFeature(f_src);
1986
                    target.insert(f_dst);
1987
                }
1988
            });
1989
            if( finishEditingAtEnd ) {
1990
                target.finishEditing();
1991
            }
1992
            
1993
        } catch(Exception ex) {
1994
            try {
1995
                if( finishEditingAtEnd ) {
1996
                    target.cancelEditing();
1997
                }
1998
            } catch (Exception ex1) {
1999
            }
2000
            throw new RuntimeException("Can't copy store.",ex);
2001
        }
2002
            
2003
    }
2004
    
2005
    //
2006
    // ====================================================================
2007
    // Obtencion de datos
2008
    // getDataCollection, getFeatureCollection
2009
    //
2010

    
2011
    @Override
2012
    public DataSet getDataSet() throws DataException {
2013
        checkNotInAppendMode();
2014
        FeatureQuery query =
2015
            new DefaultFeatureQuery(this.getDefaultFeatureType());
2016
        return new DefaultFeatureSet(this, query);
2017
    }
2018

    
2019
    @Override
2020
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2021
        checkNotInAppendMode();
2022
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2023
    }
2024

    
2025
    @Override
2026
    public void getDataSet(Observer observer) throws DataException {
2027
        checkNotInAppendMode();
2028
        this.getFeatureSet(null, observer);
2029
    }
2030

    
2031
    @Override
2032
    public void getDataSet(DataQuery dataQuery, Observer observer)
2033
        throws DataException {
2034
        checkNotInAppendMode();
2035
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2036
    }
2037

    
2038
    @Override
2039
    public FeatureSet getFeatureSet() throws DataException {
2040
        return this.getFeatureSet((FeatureQuery)null);
2041
    }
2042

    
2043
    @Override
2044
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2045
        throws DataException {
2046
        checkNotInAppendMode();
2047
        if( featureQuery==null ) {
2048
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2049
        }
2050
        return new DefaultFeatureSet(this, featureQuery);
2051
    }
2052

    
2053
    @Override
2054
    public FeatureSet getFeatureSet(String filter) throws DataException {
2055
        return this.getFeatureSet(filter, null, true);
2056
    }
2057

    
2058
    @Override
2059
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2060
        return this.getFeatureSet(filter, sortBy, true);
2061
    }
2062

    
2063
    @Override
2064
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2065
        return this.getFeatureSet(filter, null, true);
2066
    }
2067
    
2068
    @Override
2069
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2070
        return this.getFeatureSet(filter, sortBy, true);
2071
    }
2072

    
2073
    @Override
2074
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2075
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2076
        return this.getFeatureSet(query);
2077
    }
2078
    
2079
    @Override
2080
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2081
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2082
        return this.getFeatureSet(query);
2083
    }
2084
    
2085
    @Override
2086
    public List<Feature> getFeatures(String filter)  {
2087
        return this.getFeatures(filter, null, true);
2088
    }
2089

    
2090
    @Override
2091
    public List<Feature> getFeatures(String filter, String sortBy)  {
2092
        return this.getFeatures(filter, sortBy, true);
2093
    }
2094

    
2095
    @Override
2096
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
2097
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2098
        return this.getFeatures(query, 0);
2099
    }
2100
    
2101
    @Override
2102
    public List<Feature> getFeatures(Expression filter)  {
2103
        return this.getFeatures(filter, null, true);
2104
    }
2105

    
2106
    @Override
2107
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
2108
        return this.getFeatures(filter, sortBy, true);
2109
    }
2110

    
2111
    @Override
2112
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
2113
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2114
        return this.getFeatures(query, 0);
2115
    }
2116
    
2117
    @Override
2118
    public List<Feature> getFeatures(FeatureQuery query)  {
2119
        return this.getFeatures(query, 0);
2120
    }
2121
    
2122
    @Override
2123
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
2124
        try {
2125
            if( pageSize<=0 ) {
2126
                pageSize = 100;
2127
            }
2128
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2129
            return pager.asList();
2130
        } catch (BaseException ex) {
2131
            throw new RuntimeException("Can't create the list of features.", ex);
2132
        }
2133
    }
2134

    
2135
    @Override
2136
    public List<Feature> getFeatures() {
2137
        return this.getFeatures(null, 0);
2138
    }
2139

    
2140
    @Override
2141
    public GetItemWithSizeAndIterator64<Feature> getFeatures64() {
2142
        return this.getFeatures64(null, 0);
2143
    }
2144

    
2145
    @Override
2146
    public GetItemWithSizeAndIterator64<Feature> getFeatures64(String filter) {
2147
        return this.getFeatures64(filter, null, true);
2148
    }
2149
    
2150
    @Override
2151
    public GetItemWithSizeAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc)  {
2152
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2153
        return this.getFeatures64(query, 0);
2154
    }
2155

    
2156
    @Override
2157
    public GetItemWithSizeAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize)  {
2158
        try {
2159
            if( pageSize<=0 ) {
2160
                pageSize = 100;
2161
            }
2162
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2163
            return pager;
2164
        } catch (BaseException ex) {
2165
            throw new RuntimeException("Can't create the list of features.", ex);
2166
        }
2167
    }
2168

    
2169
    @Override
2170
    public Feature first() throws DataException {
2171
        return this.findFirst((FeatureQuery)null);
2172
    }
2173
    
2174
    @Override
2175
    public Feature findFirst(String filter) throws DataException {
2176
        return this.findFirst(filter, null, true);
2177
    }
2178

    
2179
    @Override
2180
    public Feature findFirst(String filter, String sortBy) throws DataException {
2181
        return this.findFirst(filter, sortBy, true);
2182
    }
2183

    
2184
    @Override
2185
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2186
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2187
        return findFirst(query);
2188
    }
2189
    
2190
    @Override
2191
    public Feature findFirst(Expression filter) throws DataException {
2192
        return this.findFirst(filter, null, true);
2193
    }
2194

    
2195
    @Override
2196
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2197
        return this.findFirst(filter, sortBy, true);
2198
    }
2199

    
2200
    @Override
2201
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2202
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2203
        return findFirst(query);
2204
    }
2205
    
2206
    @Override
2207
    public Feature findFirst(FeatureQuery query) throws DataException {
2208
        if( query == null ) {
2209
            query = this.createFeatureQuery();
2210
        } else {
2211
            query = query.getCopy();
2212
        }
2213
        query.setLimit(1);
2214
        final MutableObject<Feature> feature = new MutableObject<>();
2215
        try {
2216
            this.accept(new Visitor() {
2217
                @Override
2218
                public void visit(Object obj) throws VisitCanceledException, BaseException {
2219
                    feature.setValue((Feature) obj);
2220
                    throw new VisitCanceledException();
2221
                }
2222
            }, query);
2223
        } catch(VisitCanceledException ex) {
2224

    
2225
        } catch(DataException ex) {
2226
            throw ex;
2227
        } catch(Exception ex) {
2228
            throw new RuntimeException("", ex);
2229
        }
2230
        return feature.getValue();
2231
    }
2232

    
2233
    @Override
2234
    public void accept(Visitor visitor) throws BaseException {
2235
        this.accept(visitor, null);
2236
    }
2237

    
2238
    @Override
2239
    public void accept(Visitor visitor, DataQuery dataQuery)
2240
        throws BaseException {
2241
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2242
        try {
2243
            set.accept(visitor);
2244
        } finally {
2245
            set.dispose();
2246
        }
2247
    }
2248

    
2249
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2250
        throws DataException {
2251
        DefaultFeatureType fType =
2252
            (DefaultFeatureType) this.getFeatureType(featureQuery
2253
                .getFeatureTypeId());
2254
        if( featureQuery.hasAttributeNames() || 
2255
            featureQuery.hasConstantsAttributeNames() ||
2256
            fType.hasRequiredFields()    
2257
            ) {
2258
            if( featureQuery.hasGroupByColumns()) {
2259
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2260
            } else {
2261
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2262
            }
2263
        }
2264
        return fType;
2265
    }
2266

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

    
2273
    @Override
2274
    public void getFeatureSet(FeatureQuery query, Observer observer)
2275
        throws DataException {
2276
        class LoadInBackGround implements Runnable {
2277

    
2278
            private final FeatureStore store;
2279
            private final FeatureQuery query;
2280
            private final Observer observer;
2281

    
2282
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2283
                Observer observer) {
2284
                this.store = store;
2285
                this.query = query;
2286
                this.observer = observer;
2287
            }
2288

    
2289
            void notify(FeatureStoreNotification theNotification) {
2290
                observer.update(store, theNotification);
2291
            }
2292

    
2293
            @Override
2294
            public void run() {
2295
                FeatureSet set = null;
2296
                try {
2297
                    set = store.getFeatureSet(query);
2298
                    notify(new DefaultFeatureStoreNotification(store,
2299
                        FeatureStoreNotification.LOAD_FINISHED, set));
2300
                } catch (Exception e) {
2301
                    notify(new DefaultFeatureStoreNotification(store,
2302
                        FeatureStoreNotification.LOAD_FINISHED, e));
2303
                } finally {
2304
                    dispose(set);
2305
                }
2306
            }
2307
        }
2308

    
2309
        checkNotInAppendMode();
2310
        if (query == null) {
2311
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2312
        }
2313
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2314
        Thread thread = new Thread(task, "Load Feature Set in background");
2315
        thread.start();
2316
    }
2317

    
2318
    @Override
2319
    public Feature getFeatureByReference(FeatureReference reference)
2320
        throws DataException {
2321
        checkNotInAppendMode();
2322
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
2323
        FeatureType featureType;
2324
        if (ref.getFeatureTypeId() == null) {
2325
            featureType = this.getDefaultFeatureType();
2326
        } else {
2327
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2328
        }
2329
        return this.getFeatureByReference(reference, featureType);
2330
    }
2331

    
2332
    @Override
2333
    public Feature getFeatureByReference(FeatureReference reference,
2334
        FeatureType featureType) throws DataException {
2335
        checkNotInAppendMode();
2336
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2337
        if (this.mode == MODE_FULLEDIT) {
2338
            Feature f = featureManager.get(reference, this, featureType);
2339
            if (f != null) {
2340
                return f;
2341
            }
2342
        }
2343

    
2344
        FeatureType sourceFeatureType = featureType;
2345
        if (!this.transforms.isEmpty()) {
2346
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2347
        }
2348
        // TODO comprobar que el id es de este store
2349

    
2350
        DefaultFeature feature =
2351
            new DefaultFeature(this,
2352
                this.provider.getFeatureProviderByReference(
2353
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2354

    
2355
        if (!this.transforms.isEmpty()) {
2356
            return this.transforms.applyTransform(feature, featureType);
2357
        }
2358
        return feature;
2359
    }
2360

    
2361
    //
2362
    // ====================================================================
2363
    // Gestion de features
2364
    //
2365

    
2366
    private FeatureType fixFeatureType(DefaultFeatureType type)
2367
        throws DataException {
2368
        FeatureType original = this.getDefaultFeatureType();
2369

    
2370
        if ((type == null) || type.equals(original)) {
2371
            return original;
2372
        } else {
2373
            if (!type.isSubtypeOf(original)) {
2374
                Iterator iter = this.getFeatureTypes().iterator();
2375
                FeatureType tmpType;
2376
                boolean found = false;
2377
                while (iter.hasNext()) {
2378
                    tmpType = (FeatureType) iter.next();
2379
                    if (type.equals(tmpType)) {
2380
                        return type;
2381

    
2382
                    } else
2383
                        if (type.isSubtypeOf(tmpType)) {
2384
                            found = true;
2385
                            original = tmpType;
2386
                            break;
2387
                        }
2388

    
2389
                }
2390
                if (!found) {
2391
                    throw new IllegalFeatureTypeException(getName());
2392
                }
2393
            }
2394
        }
2395

    
2396
        // Checks that type has all fields of pk
2397
        // else add the missing attributes at the end.
2398
        if (!original.hasOID()) {
2399
            // Gets original pk attributes
2400
            DefaultEditableFeatureType edOriginal =
2401
                (DefaultEditableFeatureType) original.getEditable();
2402
            FeatureAttributeDescriptor orgAttr;
2403
            Iterator edOriginalIter = edOriginal.iterator();
2404
            while (edOriginalIter.hasNext()) {
2405
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2406
                if (!orgAttr.isPrimaryKey()) {
2407
                    edOriginalIter.remove();
2408
                }
2409
            }
2410

    
2411
            // Checks if all pk attributes are in type
2412
            Iterator typeIterator;
2413
            edOriginalIter = edOriginal.iterator();
2414
            FeatureAttributeDescriptor attr;
2415
            while (edOriginalIter.hasNext()) {
2416
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2417
                typeIterator = type.iterator();
2418
                while (typeIterator.hasNext()) {
2419
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2420
                    if (attr.getName().equals(orgAttr.getName())) {
2421
                        edOriginalIter.remove();
2422
                        break;
2423
                    }
2424
                }
2425
            }
2426

    
2427
            // add missing pk attributes if any
2428
            if (edOriginal.size() > 0) {
2429
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2430
                DefaultEditableFeatureType edType =
2431
                    (DefaultEditableFeatureType) original.getEditable();
2432
                edType.clear();
2433
                edType.addAll(type);
2434
                edType.addAll(edOriginal);
2435
                if (!isEditable) {
2436
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2437
                }
2438
            }
2439

    
2440
        }
2441

    
2442
        return type;
2443
    }
2444

    
2445
    @Override
2446
    public void validateFeatures(int mode) throws DataException {
2447
        FeatureSet collection = null;
2448
        DisposableIterator iter = null;
2449
        try {
2450
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2451
            if( rules==null || rules.isEmpty() ) {
2452
                return;
2453
            }
2454
            checkNotInAppendMode();
2455
            collection = this.getFeatureSet();
2456
            iter = collection.fastIterator();
2457
            long previousVersionOfUpdate = currentVersionOfUpdate();
2458
            while (iter.hasNext()) {
2459
                ((DefaultFeature) iter.next()).validate(mode);
2460
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2461
                    throw new ConcurrentDataModificationException(getName());
2462
                }
2463
            }
2464
        } catch (Exception e) {
2465
            throw new ValidateFeaturesException(e, getName());
2466
        } finally {
2467
            DisposeUtils.disposeQuietly(iter);
2468
            DisposeUtils.disposeQuietly(collection);
2469
        }
2470
    }
2471

    
2472
    @Override
2473
    public FeatureType getDefaultFeatureType() throws DataException {
2474
        try {
2475

    
2476
            if (isEditing()) {
2477
                FeatureType auxFeatureType =
2478
                    featureTypeManager.getType(defaultFeatureType.getId());
2479
                if (auxFeatureType != null) {
2480
                    return avoidEditable(auxFeatureType);
2481
                }
2482
            }
2483
            FeatureType type = this.transforms.getDefaultFeatureType();
2484
                if (type != null) {
2485
                return avoidEditable(type);
2486
                }
2487

    
2488
            return avoidEditable(defaultFeatureType);
2489

    
2490
        } catch (Exception e) {
2491
            throw new GetFeatureTypeException(e, getName());
2492
        }
2493
    }
2494

    
2495
    @Override
2496
    public FeatureType getDefaultFeatureTypeQuietly() {
2497
      try {
2498
        return this.getDefaultFeatureType();
2499
      } catch(Exception ex) {
2500
        return null;
2501
      }
2502
    }
2503
    
2504
    private FeatureType avoidEditable(FeatureType ft) {
2505
        if (ft instanceof EditableFeatureType) {
2506
            return ((EditableFeatureType) ft).getNotEditableCopy();
2507
        } else {
2508
            return ft;
2509
        }
2510
    }
2511

    
2512
    @Override
2513
    public FeatureType getFeatureType(String featureTypeId)
2514
        throws DataException {
2515
        if (featureTypeId == null) {
2516
            return this.getDefaultFeatureType();
2517
        }
2518
        try {
2519
            if (isEditing()) {
2520
                FeatureType auxFeatureType =
2521
                    featureTypeManager.getType(featureTypeId);
2522
                if (auxFeatureType != null) {
2523
                    return auxFeatureType;
2524
                }
2525
            }
2526
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2527
            if (type != null) {
2528
                return type;
2529
            }
2530
            Iterator iter = this.featureTypes.iterator();
2531
            while (iter.hasNext()) {
2532
                type = (FeatureType) iter.next();
2533
                if (type.getId().equals(featureTypeId)) {
2534
                    return type;
2535
                }
2536
            }
2537
            return null;
2538
        } catch (Exception e) {
2539
            throw new GetFeatureTypeException(e, getName());
2540
        }
2541
    }
2542

    
2543
    public FeatureType getProviderDefaultFeatureType() {
2544
        return defaultFeatureType;
2545
    }
2546

    
2547
    @Override
2548
    public List getFeatureTypes() throws DataException {
2549
        try {
2550
            List types;
2551
            if (isEditing()) {
2552
                types = new ArrayList();
2553
                Iterator it = featureTypes.iterator();
2554
                while (it.hasNext()) {
2555
                    FeatureType type = (FeatureType) it.next();
2556
                    FeatureType typeaux =
2557
                        featureTypeManager.getType(type.getId());
2558
                    if (typeaux != null) {
2559
                        types.add(typeaux);
2560
                    } else {
2561
                        types.add(type);
2562
                    }
2563
                }
2564
                it = featureTypeManager.newsIterator();
2565
                while (it.hasNext()) {
2566
                    FeatureType type = (FeatureType) it.next();
2567
                    types.add(type);
2568
                }
2569
            } else {
2570
                types = this.transforms.getFeatureTypes();
2571
                if (types == null) {
2572
                    types = featureTypes;
2573
                }
2574
            }
2575
            return Collections.unmodifiableList(types);
2576
        } catch (Exception e) {
2577
            throw new GetFeatureTypeException(e, getName());
2578
        }
2579
    }
2580

    
2581
    public List getProviderFeatureTypes() throws DataException {
2582
        return Collections.unmodifiableList(this.featureTypes);
2583
    }
2584

    
2585
    @Override
2586
    public Feature createFeature(FeatureProvider data) throws DataException {
2587
        DefaultFeature feature = new DefaultFeature(this, data);
2588
        return feature;
2589
    }
2590

    
2591
    public Feature createFeature(FeatureProvider data, FeatureType type)
2592
        throws DataException {
2593
        // FIXME: falta por implementar
2594
        // Comprobar si es un subtipo del feature de data
2595
        // y construir un feature usando el subtipo.
2596
        // Probablemente requiera generar una copia del data.
2597
        throw new NotYetImplemented();
2598
    }
2599

    
2600
    @Override
2601
    public EditableFeature createNewFeature(FeatureType type,
2602
        Feature defaultValues) throws DataException {
2603
        try {
2604
            FeatureProvider data = createNewFeatureProvider(type);
2605
            DefaultEditableFeature feature =
2606
                new DefaultEditableFeature(this, data);
2607
            feature.initializeValues(defaultValues);
2608
            data.setNew(true);
2609

    
2610
            return feature;
2611
        } catch (Exception e) {
2612
            throw new CreateFeatureException(e, getName());
2613
        }
2614
    }
2615

    
2616
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2617
        throws DataException {
2618
        type = this.fixFeatureType((DefaultFeatureType) type);
2619
        FeatureProvider data = this.provider.createFeatureProvider(type);
2620
        data.setNew(true);
2621
        if (type.hasOID() && (data.getOID() == null)) {
2622
            data.setOID(this.provider.createNewOID());
2623
        } else {
2624
            data.setOID(this.getTemporalOID());
2625
        }
2626
        return data;
2627

    
2628
    }
2629

    
2630
    @Override
2631
    public EditableFeature createNewFeature(FeatureType type,
2632
        boolean defaultValues) throws DataException {
2633
        try {
2634
            FeatureProvider data = createNewFeatureProvider(type);
2635
            DefaultEditableFeature feature =
2636
                new DefaultEditableFeature(this, data);
2637
            if (defaultValues) {
2638
                feature.initializeValues();
2639
            }
2640
            return feature;
2641
        } catch (Exception e) {
2642
            throw new CreateFeatureException(e, getName());
2643
        }
2644
    }
2645

    
2646
    @Override
2647
    public EditableFeature createNewFeature(boolean defaultValues)
2648
        throws DataException {
2649
        return this.createNewFeature(this.getDefaultFeatureType(),
2650
            defaultValues);
2651
    }
2652

    
2653
    @Override
2654
    public EditableFeature createNewFeature() throws DataException {
2655
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2656
    }
2657

    
2658
    @Override
2659
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2660
        FeatureType ft = this.getDefaultFeatureType();
2661
        EditableFeature f = this.createNewFeature(ft, false);
2662
        f.copyFrom(defaultValues);
2663
        return f;
2664
    }
2665

    
2666
    @Override
2667
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2668
        FeatureType ft = this.getDefaultFeatureType();
2669
        EditableFeature f = this.createNewFeature(ft, false);
2670
        f.copyFrom(defaultValues);
2671
        return f;
2672
    }
2673

    
2674
    @Override
2675
    public EditableFeatureType createFeatureType() {
2676
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2677
        return ftype;
2678
    }
2679

    
2680
    @Override
2681
    public EditableFeatureType createFeatureType(String id) {
2682
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2683
        return ftype;
2684
    }
2685

    
2686
    //
2687
    // ====================================================================
2688
    // Index related methods
2689
    //
2690

    
2691
    @Override
2692
    public FeatureIndexes getIndexes() {
2693
        return this.indexes;
2694
    }
2695

    
2696
    @Override
2697
    public FeatureIndex createIndex(FeatureType featureType,
2698
        String attributeName, String indexName) throws DataException {
2699
        return createIndex(null, featureType, attributeName, indexName);
2700
    }
2701

    
2702
    @Override
2703
    public FeatureIndex createIndex(String indexTypeName,
2704
        FeatureType featureType, String attributeName, String indexName)
2705
        throws DataException {
2706

    
2707
        return createIndex(indexTypeName, featureType, attributeName,
2708
            indexName, false, null);
2709
    }
2710

    
2711
    @Override
2712
    public FeatureIndex createIndex(FeatureType featureType,
2713
        String attributeName, String indexName, Observer observer)
2714
        throws DataException {
2715
        return createIndex(null, featureType, attributeName, indexName,
2716
            observer);
2717
    }
2718

    
2719
    @Override
2720
    public FeatureIndex createIndex(String indexTypeName,
2721
        FeatureType featureType, String attributeName, String indexName,
2722
        final Observer observer) throws DataException {
2723

    
2724
        return createIndex(indexTypeName, featureType, attributeName,
2725
            indexName, true, observer);
2726
    }
2727

    
2728
    private FeatureIndex createIndex(String indexTypeName,
2729
        FeatureType featureType, String attributeName, String indexName,
2730
        boolean background, final Observer observer) throws DataException {
2731

    
2732
        checkNotInAppendMode();
2733
        FeatureIndexProviderServices index;
2734
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2735
                featureType, indexName,
2736
                featureType.getAttributeDescriptor(attributeName));
2737

    
2738
        try {
2739
            index.fill(background, observer);
2740
        } catch (FeatureIndexException e) {
2741
            throw new InitializeException(index.getName(), e);
2742
        }
2743

    
2744
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2745
        return index;
2746
    }
2747

    
2748
    //
2749
    // ====================================================================
2750
    // Transforms related methods
2751
    //
2752

    
2753
    @Override
2754
    public FeatureStoreTransforms getTransforms() {
2755
        return this.transforms;
2756
    }
2757

    
2758
    @Override
2759
    public FeatureQuery createFeatureQuery() {
2760
        return new DefaultFeatureQuery();
2761
    }
2762
    
2763
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
2764
        FeatureQuery query = null;
2765
        if( filter!=null ) {
2766
            query = this.createFeatureQuery();
2767
            query.setFilter(filter);
2768
        }
2769
        if( !StringUtils.isEmpty(sortBy) ) {
2770
            if( query == null ) {
2771
                query = this.createFeatureQuery();
2772
            }
2773
            String[] attrnames;
2774
            if( sortBy.contains(",") ) {
2775
                attrnames = StringUtils.split(sortBy, ",");
2776
            } else {
2777
                attrnames = new String[] { sortBy };
2778
            }
2779
            for (String attrname : attrnames) {
2780
                attrname = attrname.trim();
2781
                if( attrname.startsWith("-") ) {
2782
                    query.getOrder().add(sortBy.substring(1).trim(), false);
2783
                } else if( attrname.endsWith("-") ) { 
2784
                    query.getOrder().add(sortBy.substring(0,sortBy.length()-1).trim(), false);
2785
                } else if( attrname.startsWith("+") ) {
2786
                    query.getOrder().add(sortBy.substring(1).trim(), true);
2787
                } else if( attrname.endsWith("-") ) { 
2788
                    query.getOrder().add(sortBy.substring(0,sortBy.length()-1).trim(), true);
2789
                } else {
2790
                    query.getOrder().add(sortBy, asc);
2791
                }
2792
            }
2793
        }
2794
        if( query != null ) {
2795
            query.retrievesAllAttributes();
2796
        }
2797
        return query;
2798
    }
2799
    
2800
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
2801
        if( StringUtils.isBlank(filter) ) {
2802
            return this.createFeatureQuery(
2803
                    (Expression)null, 
2804
                    sortBy, 
2805
                    asc
2806
            );
2807
        } else {
2808
            return this.createFeatureQuery(
2809
                    ExpressionUtils.createExpression(filter), 
2810
                    sortBy, 
2811
                    asc
2812
            );
2813
        }
2814
    }
2815
    
2816
    @Override
2817
    public DataQuery createQuery() {
2818
        return createFeatureQuery();
2819
    }
2820

    
2821
    //
2822
    // ====================================================================
2823
    // UndoRedo related methods
2824
    //
2825

    
2826
    @Override
2827
    public boolean canRedo() {
2828
        return commands.canRedo();
2829
    }
2830

    
2831
    @Override
2832
    public boolean canUndo() {
2833
        return commands.canUndo();
2834
    }
2835

    
2836
    @Override
2837
    public void redo(int num) throws RedoException {
2838
        for (int i = 0; i < num; i++) {
2839
            redo();
2840
        }
2841
    }
2842

    
2843
    @Override
2844
    public void undo(int num) throws UndoException {
2845
        for (int i = 0; i < num; i++) {
2846
            undo();
2847
        }
2848
    }
2849

    
2850
    //
2851
    // ====================================================================
2852
    // Metadata related methods
2853
    //
2854

    
2855
    @Override
2856
    public Object getMetadataID() {
2857
        return this.provider.getSourceId();
2858
    }
2859

    
2860
    @Override
2861
    public void delegate(DynObject dynObject) {
2862
        this.metadata.delegate(dynObject);
2863
    }
2864

    
2865
    @Override
2866
    public DynClass getDynClass() {
2867
        return this.metadata.getDynClass();
2868
    }
2869

    
2870
    @Override
2871
    public Object getDynValue(String name) throws DynFieldNotFoundException {
2872
        try {
2873
            if (this.transforms.hasDynValue(name)) {
2874
                return this.transforms.getDynValue(name);
2875
            }
2876
            if (this.metadata.hasDynValue(name)) {
2877
                return this.metadata.getDynValue(name);
2878
            }
2879
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2880
                return this.provider.getProviderName();
2881
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2882
                return this.provider.getSourceId();
2883
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2884
                try {
2885
                    return this.getDefaultFeatureType();
2886
                } catch (DataException e) {
2887
                    return null;
2888
                }
2889
            }
2890
            return this.metadata.getDynValue(name);
2891
        } catch(Exception ex ) {
2892
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
2893
            return null;
2894
        }
2895
    }
2896

    
2897
    @Override
2898
    public boolean hasDynValue(String name) {
2899
        if (this.transforms.hasDynValue(name)) {
2900
            return true;
2901
        }
2902
        return this.metadata.hasDynValue(name);
2903
    }
2904

    
2905
    @Override
2906
    public boolean hasDynMethod(String name) {
2907
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2908
    }
2909

    
2910
    @Override
2911
    public void implement(DynClass dynClass) {
2912
        this.metadata.implement(dynClass);
2913
    }
2914

    
2915
    @Override
2916
    public Object invokeDynMethod(String name, Object[] args)
2917
        throws DynMethodException {
2918
        return this.metadata.invokeDynMethod(this, name, args);
2919
    }
2920

    
2921
    @Override
2922
    public Object invokeDynMethod(int code, Object[] args)
2923
        throws DynMethodException {
2924
        return this.metadata.invokeDynMethod(this, code, args);
2925
    }
2926

    
2927
    @Override
2928
    public void setDynValue(String name, Object value)
2929
        throws DynFieldNotFoundException {
2930
                if( this.transforms.hasDynValue(name) ) {
2931
                        this.transforms.setDynValue(name, value);
2932
                        return;
2933
                }
2934
        this.metadata.setDynValue(name, value);
2935

    
2936
    }
2937

    
2938
    /*
2939
     * (non-Javadoc)
2940
     *
2941
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2942
     */
2943
    @Override
2944
    public Set getMetadataChildren() {
2945
        return this.metadataChildren;
2946
    }
2947

    
2948
    /*
2949
     * (non-Javadoc)
2950
     *
2951
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2952
     */
2953
    @Override
2954
    public String getMetadataName() {
2955
        return this.provider.getProviderName();
2956
    }
2957

    
2958
    public FeatureTypeManager getFeatureTypeManager() {
2959
        return this.featureTypeManager;
2960
    }
2961

    
2962
    @Override
2963
    public long getFeatureCount() throws DataException {
2964
        if (featureCount == null) {
2965
            featureCount = this.provider.getFeatureCount();
2966
        }
2967
        if (this.isEditing()) {
2968
            if(this.isAppending()) {
2969
                try{
2970
                    throw new IllegalStateException();
2971
                } catch(IllegalStateException e) {
2972
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
2973
                }
2974
                return -1;
2975
            } else {
2976
                return featureCount
2977
                    + this.featureManager.getDeltaSize();
2978
            }
2979
        }
2980
        return featureCount;
2981
    }
2982

    
2983
    private Long getTemporalOID() {
2984
        return this.temporalOid++;
2985
    }
2986

    
2987
    @Override
2988
    public FeatureType getProviderFeatureType(String featureTypeId) {
2989
        if (featureTypeId == null) {
2990
            return this.defaultFeatureType;
2991
        }
2992
        FeatureType type;
2993
        Iterator iter = this.featureTypes.iterator();
2994
        while (iter.hasNext()) {
2995
            type = (FeatureType) iter.next();
2996
            if (type.getId().equals(featureTypeId)) {
2997
                return type;
2998
            }
2999
        }
3000
        return null;
3001
    }
3002

    
3003
    @Override
3004
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3005
        return ((DefaultFeature) feature).getData();
3006
    }
3007

    
3008
    @Override
3009
    public DataStore getStore() {
3010
        return this;
3011
    }
3012

    
3013
    @Override
3014
    public FeatureStore getFeatureStore() {
3015
        return this;
3016
    }
3017

    
3018
    @Override
3019
    public void createCache(String name, DynObject parameters)
3020
        throws DataException {
3021
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3022
        if (cache == null) {
3023
            throw new CreateException("FeaureCacheProvider", null);
3024
        }
3025
        cache.apply(this, provider);
3026
        provider = cache;
3027

    
3028
        featureCount = null;
3029
    }
3030

    
3031
    @Override
3032
    public FeatureCache getCache() {
3033
        return cache;
3034
    }
3035

    
3036
    @Override
3037
    public void clear() {
3038
        if (metadata != null) {
3039
            metadata.clear();
3040
        }
3041
    }
3042

    
3043
    @Override
3044
    public String getName() {
3045
        if( this.provider != null ) {
3046
            return this.provider.getName();
3047
        }
3048
        if( this.parameters instanceof HasAFile ) {
3049
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
3050
        }
3051
        return "unknow";
3052
    }
3053

    
3054
    @Override
3055
    public String getFullName() {
3056
        try {
3057
            if( this.provider!=null ) {
3058
                return this.provider.getFullName();
3059
            }
3060
            if( this.parameters instanceof HasAFile ) {
3061
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
3062
            }
3063
            return null;
3064
        } catch(Throwable th) {
3065
            return null;
3066
        }
3067
    }
3068

    
3069
    @Override
3070
    public String getProviderName() {
3071
        if( this.provider!=null ) {
3072
            return this.provider.getProviderName();
3073
        }
3074
        if( this.parameters != null ) {
3075
            return this.parameters.getDataStoreName();
3076
        }
3077
        return null;
3078

    
3079
    }
3080

    
3081
    @Override
3082
    public boolean isKnownEnvelope() {
3083
        return this.provider.isKnownEnvelope();
3084
    }
3085

    
3086
    @Override
3087
    public boolean hasRetrievedFeaturesLimit() {
3088
        return this.provider.hasRetrievedFeaturesLimit();
3089
    }
3090

    
3091
    @Override
3092
    public int getRetrievedFeaturesLimit() {
3093
        return this.provider.getRetrievedFeaturesLimit();
3094
    }
3095

    
3096
    @Override
3097
    public Interval getInterval() {
3098
        if( this.timeSupport!=null ) {
3099
            return this.timeSupport.getInterval();
3100
        }
3101
        try {
3102
            FeatureType type = this.getDefaultFeatureType();
3103
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3104
            if( attr!=null ) {
3105
                Interval interval = attr.getInterval();
3106
                if( interval!=null ) {
3107
                    return interval;
3108
                }
3109
            }
3110
        } catch (DataException ex) {
3111
        }
3112
        return this.provider.getInterval();
3113
    }
3114

    
3115
    @Override
3116
    public Collection getTimes() {
3117
        if( this.timeSupport!=null ) {
3118
            return this.timeSupport.getTimes();
3119
        }
3120
        return this.provider.getTimes();
3121
    }
3122

    
3123
    @Override
3124
    public Collection getTimes(Interval interval) {
3125
        if( this.timeSupport!=null ) {
3126
            return this.timeSupport.getTimes(interval);
3127
        }
3128
        return this.provider.getTimes(interval);
3129
    }
3130

    
3131
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3132
        if( this.isEditing() ) {
3133
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
3134
        }
3135
        if( !this.transforms.isEmpty() ) {
3136
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
3137
        }
3138
        FeatureType ft = this.defaultFeatureType;
3139
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3140
        if( attr == null ) {
3141
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
3142
        }
3143
        EditableFeatureType eft = ft.getEditable();
3144
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3145
        if( attr != null ) {
3146
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
3147
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
3148
            }
3149
            eft.remove(attr.getName());
3150
        }
3151
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3152
            timeSupport.getAttributeName(), 
3153
            timeSupport.getDataType()
3154
        );
3155
        attrTime.setIsTime(true);
3156
        attrTime.setFeatureAttributeEmulator(timeSupport);
3157
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3158
        this.defaultFeatureType = eft.getNotEditableCopy();
3159
        
3160
        this.timeSupport = timeSupport;
3161
    }
3162

    
3163
    @Override
3164
    @SuppressWarnings("CloneDoesntCallSuperClone")
3165
    public Object clone() throws CloneNotSupportedException {
3166

    
3167
        DataStoreParameters dsp = getParameters();
3168

    
3169
        DefaultFeatureStore cloned_store = null;
3170

    
3171
        try {
3172
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3173
                openStore(this.getProviderName(), dsp);
3174
            if (transforms != null) {
3175
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3176
                cloned_store.transforms.setStoreForClone(cloned_store);
3177
            }
3178
        } catch (Exception e) {
3179
            throw new CloneException(e);
3180
        }
3181
        return cloned_store;
3182

    
3183
    }
3184

    
3185
    @Override
3186
    public Feature getFeature(DynObject dynobject) {
3187
        if (dynobject instanceof DynObjectFeatureFacade){
3188
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
3189
            return f;
3190
        }
3191
        return null;
3192
    }
3193

    
3194
    @Override
3195
    public Iterator iterator() {
3196
        FeatureSet fset = null;
3197
        try {
3198
            fset  = this.getFeatureSet();
3199
            return fset.fastIterator();
3200
        } catch (DataException ex) {
3201
            throw new RuntimeException(ex);
3202
        } finally {
3203
            DisposeUtils.disposeQuietly(fset);
3204
        }
3205
    }
3206

    
3207
    @Override
3208
    public long size64() {
3209
        FeatureSet fset = null;
3210
        try {
3211
            fset  = this.getFeatureSet();
3212
            return fset.getSize();
3213
        } catch (DataException ex) {
3214
            throw new RuntimeException(ex);
3215
        } finally {
3216
            DisposeUtils.disposeQuietly(fset);
3217
        }
3218
    }
3219
   
3220
    @Override
3221
    public ExpressionBuilder createExpressionBuilder() {
3222
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3223
        return builder;
3224
    }
3225

    
3226
    @Override
3227
    public ExpressionBuilder createExpression() {
3228
        return createExpressionBuilder();
3229
    }
3230

    
3231
    public FeatureSet features() throws DataException {
3232
        // This is to avoid jython to create a property with this name
3233
        // to access method getFeatures.
3234
        return this.getFeatureSet();
3235
    }
3236

    
3237
    @Override
3238
    public DataStoreProviderFactory getProviderFactory() {
3239
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3240
        return factory;
3241
    }
3242

    
3243
    @Override
3244
    public void useCache(String providerName, DynObject parameters) throws DataException {
3245
        throw new UnsupportedOperationException();
3246
    }
3247

    
3248
    @Override
3249
    public boolean isBroken() {
3250
        return this.state.isBroken();
3251
    }
3252

    
3253
    @Override
3254
    public Throwable getBreakingsCause() {
3255
            return this.state.getBreakingsCause();
3256
    }
3257

    
3258
    @Override
3259
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3260
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3261
      if( !factory.supportNumericOID() ) {
3262
          return null;
3263
      }
3264
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3265
      return wrappedIndex;
3266
  }
3267

    
3268
    @Override
3269
    public FeatureReference getFeatureReference(String code) {
3270
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
3271
        return featureReference;
3272
    }
3273

    
3274
    @Override
3275
    public long getPendingChangesCount() {
3276
        if( this.featureManager==null ) {
3277
            return 0;
3278
        }
3279
        return this.featureManager.getPendingChangesCount();
3280
    }
3281

    
3282
    @Override
3283
    public ResourcesStorage getResourcesStorage() {
3284
        ResourcesStorage resourcesStorage;
3285
        try {
3286
            resourcesStorage = this.provider.getResourcesStorage();
3287
            if( resourcesStorage!=null ) {
3288
                return resourcesStorage;
3289
            }
3290
        } catch(Throwable th) {
3291
            
3292
        }
3293
        try {
3294
            DataServerExplorer explorer = this.getExplorer();
3295
            if( explorer==null ) {
3296
                return null;
3297
            }
3298
            resourcesStorage = explorer.getResourcesStorage(this);
3299
            explorer.dispose();
3300
            return resourcesStorage;
3301
        } catch (Exception ex) {
3302
            LOGGER.warn("Can't create resources storage",ex);
3303
            return null;
3304
        }
3305
    }
3306

    
3307
    @Override
3308
    public StoresRepository getStoresRepository() {
3309
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3310
        StoresRepository localRepository = this.provider.getStoresRepository();
3311
        if( localRepository==null ) {
3312
            return mainRepository;
3313
        }
3314
        StoresRepository repository = new BaseStoresRepository(this.getName());
3315
        repository.addRepository(localRepository);
3316
        repository.addRepository(mainRepository);
3317
        return repository;
3318
    }
3319

    
3320
    @Override
3321
    public Feature getSampleFeature() {
3322
            Feature sampleFeature;
3323
            try {
3324
                FeatureSelection theSelection = this.getFeatureSelection();
3325
                if( theSelection!=null && !theSelection.isEmpty() ) {
3326
                    sampleFeature = theSelection.first();
3327
                } else {
3328
                    sampleFeature = this.first();
3329
                }
3330
                if( sampleFeature==null ) {
3331
                    sampleFeature = this.createNewFeature();
3332
                }
3333
            } catch (DataException ex) {
3334
                return null;
3335
            }
3336
            return sampleFeature;
3337
    }
3338

    
3339
    @Override
3340
    public boolean supportReferences() {
3341
        try {
3342
            return this.getDefaultFeatureType().supportReferences();
3343
        } catch (Exception ex) {
3344
            return false;
3345
        }
3346
    }
3347

    
3348
    @Override
3349
    public boolean isTemporary() {
3350
        if( this.provider==null ) {
3351
            return true;
3352
        }
3353
        return this.provider.isTemporary();
3354
    }
3355
    
3356
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3357
        // FIXME this don't work for Store.fType.size() > 1
3358
        FeatureTypeManager manager = this.featureTypeManager;
3359
         if (manager==null) {
3360
             return null;
3361
         }
3362
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3363
         if (originalFeatureType==null) {
3364
             return null;
3365
         }
3366
         return originalFeatureType.getCopy();
3367
    }
3368

    
3369
    @Override
3370
    public Object getProperty(String name) {
3371
        if( this.propertiesSupportHelper==null ) {
3372
            return null;
3373
        }
3374
        return this.propertiesSupportHelper.getProperty(name);
3375
    }
3376

    
3377
    @Override
3378
    public void setProperty(String name, Object value) {
3379
        if( this.propertiesSupportHelper==null ) {
3380
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3381
        }
3382
        this.propertiesSupportHelper.setProperty(name,value);
3383
    }
3384

    
3385
    @Override
3386
    public Map<String, Object> getProperties() {
3387
        if( this.propertiesSupportHelper==null ) {
3388
            return Collections.EMPTY_MAP;
3389
        }
3390
        return this.propertiesSupportHelper.getProperties();
3391
    }
3392
    
3393

    
3394

    
3395
}