Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.impl / src / main / java / org / gvsig / fmap / dal / feature / impl / DefaultFeatureStore.java @ 45647

History | View | Annotate | Download (125 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

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

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

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

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

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

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

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

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

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

    
210
    private DefaultDataManager dataManager = null;
211

    
212
    private FeatureStoreProvider provider = null;
213

    
214
    private DefaultFeatureIndexes indexes;
215

    
216
    private DefaultFeatureStoreTransforms transforms;
217

    
218
    /*friend*/ DelegatedDynObject metadata;
219

    
220
    private Set metadataChildren;
221

    
222
    private Long featureCount = null;
223

    
224
    private long temporalOid = 0;
225

    
226
    private FeatureCacheProvider cache;
227

    
228
    private final StateInformation state;
229

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

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

    
236
        private static final long serialVersionUID = 4109026189635185666L;
237

    
238
        private boolean broken;
239
        private Throwable breakingsCause;
240

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

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

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

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

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

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

    
273

    
274

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

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

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

    
297
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
298

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

    
304
        this.dataManager = (DefaultDataManager) dataManager;
305

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

    
314
    }
315

    
316
    @Override
317
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
318
        this.provider = (FeatureStoreProvider) provider;
319
        this.delegate((DynObject) provider);
320
        this.metadataChildren = new HashSet();
321
        this.metadataChildren.add(provider);
322
        loadDALFile();
323

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
622
        }
623

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

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

    
631
    }
632

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

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

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

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

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

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

    
745
                    }
746

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

    
752

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1038
    }
1039

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

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

    
1049
    }
1050

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

    
1055
    }
1056

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

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

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

    
1075
    }
1076

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

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

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

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

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

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

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

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

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

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

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

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

    
1152
        }
1153

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

    
1158
        featureCount = null;
1159

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1448
            //Update the featureManager and the spatialManager
1449
            featureManager.delete(feature);
1450
            spatialManager.deleteFeature(feature);
1451

    
1452
            newVersionOfUpdate();
1453
            hasStrongChanges = true;
1454
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1455
        } catch (Exception e) {
1456
            throw new StoreDeleteFeatureException(e, this.getName());
1457
        }
1458
    }
1459

    
1460
    @Override
1461
    public synchronized void insert(FeatureSet set) throws DataException {
1462
        switch (mode) {
1463
        case MODE_QUERY:
1464
            throw new NeedEditingModeException(this.getName());
1465

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

    
1483
    @Override
1484
    public synchronized void insert(EditableFeature feature)
1485
        throws DataException {
1486
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1487
        try {
1488
            switch (mode) {
1489
            case MODE_QUERY:
1490
                throw new NeedEditingModeException(this.getName());
1491

    
1492
            case MODE_APPEND:
1493
                checkIsOwnFeature(feature);
1494
                if (feature.isUpdatable() ) {
1495
                    throw new NoNewFeatureInsertException(this.getName());
1496
                }
1497
                if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1498
                  return;
1499
                }
1500
                this.featureCount = null;
1501
                feature.validate(Feature.UPDATE);
1502
                provider.append(((DefaultEditableFeature) feature).getData());
1503
                hasStrongChanges = true;
1504
                hasInserts = true;
1505
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1506
                break;
1507

    
1508
            case MODE_FULLEDIT:
1509
                if (feature.isUpdatable() ) {
1510
                    throw new NoNewFeatureInsertException(this.getName());
1511
                }
1512
                feature.validate(Feature.UPDATE);
1513
                commands.insert(feature);
1514
                break;
1515
                
1516
            case MODE_PASS_THROUGH:
1517
                checkIsOwnFeature(feature);
1518
                if (feature.isUpdatable() ) {
1519
                    throw new NoNewFeatureInsertException(this.getName());
1520
                }
1521
                if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1522
                  return;
1523
                }
1524
                feature.validate(Feature.UPDATE);
1525
                this.provider.passThroughInsert(((DefaultEditableFeature) feature).getData());
1526
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1527
                break;
1528
            }
1529
        } catch (Exception e) {
1530
            throw new StoreInsertFeatureException(e, this.getName());
1531
        }
1532
    }
1533

    
1534
    synchronized public void doInsert(EditableFeature feature)
1535
        throws DataException {
1536
        checkIsOwnFeature(feature);
1537

    
1538
        waitForIndexes();
1539

    
1540
        if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1541
          return;
1542
        }
1543
        newVersionOfUpdate();
1544
        if ((lastChangedFeature == null)
1545
            || (lastChangedFeature.getSource() != feature.getSource())) {
1546
            lastChangedFeature = feature;
1547
            feature.validate(Feature.UPDATE);
1548
            lastChangedFeature = null;
1549
        }
1550
        //Update the featureManager and the spatialManager
1551
        ((DefaultFeature) feature).setInserted(true);
1552
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1553

    
1554

    
1555
        featureManager.add(newFeature);
1556
        spatialManager.insertFeature(newFeature);
1557

    
1558
        hasStrongChanges = true;
1559
        hasInserts = true;
1560
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1561
    }
1562

    
1563
    @Override
1564
    public void update(EditableFeature feature)
1565
    throws DataException {
1566
        switch (this.mode){
1567
        case MODE_PASS_THROUGH:
1568
            checkIsOwnFeature(feature);
1569
            if (!feature.isUpdatable()) {
1570
                throw new NoNewFeatureInsertException(this.getName());
1571
            }
1572
            if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1573
              return;
1574
            }
1575
            feature.validate(Feature.UPDATE);
1576
            this.provider.passThroughUpdate(((DefaultEditableFeature)feature).getData());
1577
            notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1578
            break;
1579
        case MODE_FULLEDIT:
1580
            if (feature.isUpdatable()) {
1581
                commands.update(feature, feature.getSource());
1582
                return;
1583
            }
1584
            // FIXME: Deberiamos lanzar aqui un error en lugar de hacer el insert.
1585
            //        O lanzar un mensaje al log?
1586
            insert(feature);
1587
            break;
1588
        default:
1589
            throw new NeedEditingModeException(this.getName());
1590
        }
1591
    }
1592

    
1593
    @Override
1594
    public void update(Object... parameters) throws DataException {
1595
        if(parameters.length == 1){
1596
            this.update((EditableFeature)parameters[0]);
1597
            return;
1598
        }
1599
        
1600
        Expression filter = null;
1601
        long end = parameters.length;
1602
        if(parameters.length % 2 == 1){
1603
            Object param = parameters[parameters.length-1];
1604
            if(param != null){
1605
                if(param instanceof Expression){
1606
                    filter = (Expression) param;
1607
                } else {
1608
                    filter = ExpressionUtils.createExpression(param.toString());
1609
                }
1610
            }
1611
        } else {
1612
            end = parameters.length-1;
1613
        }
1614
        
1615
        switch (this.mode){
1616
        case MODE_PASS_THROUGH:
1617
            this.provider.passThroughUpdate(
1618
//                    this.getName(), 
1619
                    parameters, 
1620
                    filter);
1621
            break;
1622
        case MODE_FULLEDIT:
1623
            FeatureSet set = this.getFeatureSet(filter);
1624
            DisposableIterator it = set.fastIterator();
1625
            while (it.hasNext()) {
1626
                Feature feature = (Feature) it.next();
1627
                EditableFeature ef = feature.getEditable();
1628
                for (int i = 0; i < end; i+=2) {
1629
                    String name = (String) parameters[i];
1630
                    Object value = parameters[i+1];
1631
                    ef.set(name, value);
1632
                }
1633
                set.update(ef);
1634
            }
1635
            DisposeUtils.disposeQuietly(it);
1636
            DisposeUtils.disposeQuietly(set);
1637
            break;
1638
        default:
1639
            throw new NeedEditingModeException(this.getName());
1640
        }
1641
    }
1642

    
1643
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1644
        throws DataException {
1645
        try {
1646
            checkInEditingMode();
1647
            checkIsOwnFeature(feature);
1648
            if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled() ) {
1649
              return;
1650
            }
1651
            newVersionOfUpdate();
1652
            if ((lastChangedFeature == null)
1653
                || (lastChangedFeature.getSource() != feature.getSource())) {
1654
                lastChangedFeature = feature;
1655
                feature.validate(Feature.UPDATE);
1656
                lastChangedFeature = null;
1657
            }
1658

    
1659
            //Update the featureManager and the spatialManager
1660
            Feature newf = feature.getNotEditableCopy();
1661
            featureManager.update(newf, oldFeature);
1662
            spatialManager.updateFeature(newf, oldFeature);
1663

    
1664
            hasStrongChanges = true;
1665
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1666
        } catch (Exception e) {
1667
            throw new StoreUpdateFeatureException(e, this.getName());
1668
        }
1669
    }
1670

    
1671
    @Override
1672
    synchronized public void redo() throws RedoException {
1673
        Command redo = commands.getNextRedoCommand();
1674
        try {
1675
            checkInEditingMode();
1676
        } catch (NeedEditingModeException ex) {
1677
            throw new RedoException(redo, ex);
1678
        }
1679
        if( notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled() ) {
1680
          return;
1681
        }
1682
        newVersionOfUpdate();
1683
        commands.redo();
1684
        hasStrongChanges = true;
1685
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1686
    }
1687

    
1688
    @Override
1689
    synchronized public void undo() throws UndoException {
1690
        Command undo = commands.getNextUndoCommand();
1691
        try {
1692
            checkInEditingMode();
1693
        } catch (NeedEditingModeException ex) {
1694
            throw new UndoException(undo, ex);
1695
        }
1696
        if( notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled() ) {
1697
          return;
1698
        }
1699
        newVersionOfUpdate();
1700
        commands.undo();
1701
        hasStrongChanges = true;
1702
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1703
    }
1704

    
1705
    @Override
1706
    public List getRedoInfos() {
1707
        if (isEditing() && (commands != null)) {
1708
            return commands.getRedoInfos();
1709
        } else {
1710
            return null;
1711
        }
1712
    }
1713

    
1714
    @Override
1715
    public List getUndoInfos() {
1716
        if (isEditing() && (commands != null)) {
1717
            return commands.getUndoInfos();
1718
        } else {
1719
            return null;
1720
        }
1721
    }
1722

    
1723
    public synchronized FeatureCommandsStack getCommandsStack()
1724
        throws DataException {
1725
        checkInEditingMode();
1726
        return commands;
1727
    }
1728

    
1729
    @Override
1730
    public boolean cancelEditingQuietly() {
1731
        try {
1732
            this.cancelEditing();
1733
            return true;
1734
        } catch(Exception ex) {
1735
            LOGGER.debug("Can't cancel editing", ex);
1736
            return false;
1737
        }
1738
    }
1739
    
1740
    @Override
1741
    synchronized public void cancelEditing() throws DataException {
1742
        if( spatialManager!=null ) {
1743
            spatialManager.cancelModifies();
1744
        }
1745
        try {
1746
            switch (mode) {
1747
            case MODE_QUERY:
1748
                throw new NeedEditingModeException(this.getName());
1749

    
1750
            case MODE_APPEND:
1751
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1752
                  return;
1753
                }
1754
                provider.abortAppend();
1755
                exitEditingMode();
1756
                ((FeatureSelection) this.getSelection()).deselectAll();
1757
                updateIndexes();
1758
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1759
                break;
1760

    
1761
            case MODE_FULLEDIT:
1762
                boolean clearSelection = this.hasStrongChanges;
1763
                if (this.selection instanceof FeatureReferenceSelection) {
1764
                    clearSelection = this.hasInserts;
1765
                }
1766
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1767
                  return;
1768
                }
1769
                exitEditingMode();
1770
                if (clearSelection) {
1771
                    ((FeatureSelection) this.getSelection()).deselectAll();
1772
                }
1773
                updateIndexes();
1774
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);  
1775
                break;
1776

    
1777
            case MODE_PASS_THROUGH:
1778
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1779
                  return;
1780
                }
1781
                exitEditingMode();
1782
                ((FeatureSelection) this.getSelection()).deselectAll();
1783
                updateIndexes();
1784
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);  
1785
                break;
1786
            }
1787
        } catch (Exception e) {
1788
            throw new StoreCancelEditingException(e, this.getName());
1789
        }
1790
    }
1791

    
1792
    @Override
1793
    public boolean finishEditingQuietly() {
1794
        try {
1795
            this.finishEditing();
1796
            return true;
1797
        } catch(Exception ex) {
1798
            LOGGER.debug("Can't finish editing", ex);
1799
            return false;
1800
        }
1801
    }
1802
    
1803
    @Override
1804
    synchronized public void finishEditing() throws DataException {
1805
        LOGGER.debug("finish editing of mode: {}", mode);
1806
        try {
1807

    
1808
            /*
1809
             * Selection needs to be cleared when editing stops
1810
             * to prevent conflicts with selection remaining from
1811
             * editing mode.
1812
             */
1813
//            ((FeatureSelection) this.getSelection()).deselectAll();
1814
            Map<String,List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1815
            switch (mode) {
1816
            case MODE_QUERY:
1817
                throw new NeedEditingModeException(this.getName());
1818

    
1819
            case MODE_APPEND:
1820
                if( selection!=null ) {
1821
                    selection = null;
1822
                }
1823
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled() ) {
1824
                  return;
1825
                }
1826
                saveDALFile();
1827
                provider.endAppend();
1828
                exitEditingMode();
1829
                this.updateComputedFields(computedFields);
1830
                loadDALFile();
1831
                updateIndexes();
1832
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1833
                break;
1834

    
1835
            case MODE_FULLEDIT:
1836
                if( featureManager.hasChanges() || featureTypeManager.hasChanges() )  {
1837
                    if (hasStrongChanges && !this.allowWrite()) {
1838
                        throw new WriteNotAllowedException(getName());
1839
                    }
1840
                    if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, 
1841
                            featureManager.getDeleted(),
1842
                            featureManager.getInsertedFeatures(),
1843
                            featureManager.getUpdatedFeatures(),
1844
                            featureTypeManager.getFeatureTypesChanged().iterator(),
1845
                            featureManager.isSelectionCompromised()).isCanceled() ) {
1846
                      return;
1847
                    }
1848
                    saveDALFile();
1849
                    if(featureManager.isSelectionCompromised() && selection!=null ) {
1850
                        selection = null;
1851
                    }
1852
                    if (hasStrongChanges) {
1853
                        validateFeatures(Feature.FINISH_EDITING);
1854

    
1855
                        /*
1856
                         * This will throw a PerformEditingExceptionif the provider
1857
                         * does not accept the changes (for example, an invalid field name)
1858
                         */
1859
                        provider.performChanges(featureManager.getDeleted(),
1860
                            featureManager.getInserted(),
1861
                            featureManager.getUpdated(),
1862
                            removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1863

    
1864
                    }  
1865
                    this.updateComputedFields(computedFields);
1866
                    exitEditingMode();
1867
                    loadDALFile();
1868
                    updateIndexes();
1869
                    notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1870
                } else {
1871
                    exitEditingMode();
1872
                }
1873
                break;
1874
            case MODE_PASS_THROUGH:
1875
                if( selection!=null ) {
1876
                    selection = null;
1877
                }
1878
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled() ) {
1879
                  return;
1880
                }
1881
                exitEditingMode();
1882
                updateIndexes();
1883
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1884
                break;
1885
            }
1886
        } catch (PerformEditingException pee) {
1887
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
1888
            throw new WriteException(provider.getSourceId().toString(), pee);
1889
        } catch (Exception e) {
1890
            notifyChange(FeatureStoreNotification.FAILED_FINISHEDITING);
1891
            throw new FinishEditingException(e);
1892
        }
1893
    }
1894
    private Map<String,List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
1895
        Map<String,List<FeatureAttributeDescriptor>> r = new HashMap<>();
1896
        
1897
        List<FeatureType> theTypes = new ArrayList<>();
1898
        theTypes.addAll(this.getFeatureTypes());
1899
        theTypes.add(this.getDefaultFeatureType());
1900
        for( int n=0; n<theTypes.size(); n++ ) {
1901
            FeatureType type = theTypes.get(n);
1902
                for (FeatureAttributeDescriptor attrdesc : type) {
1903
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
1904
                    if( emulator!= null) {
1905
                        List<FeatureAttributeDescriptor> l = r.get(type.getId());
1906
                        if (l==null) {
1907
                            l = new ArrayList<>();
1908
                            r.put(type.getId(), l);
1909
                        }
1910
                        l.add(attrdesc);
1911
                    }
1912
            }
1913
        }
1914
        return r;
1915
    }
1916
    private void updateComputedFields(Map<String,List<FeatureAttributeDescriptor>> computedFields) throws DataException {
1917

    
1918
        List<FeatureType> theTypes = new ArrayList<>();
1919
        theTypes.addAll(this.getFeatureTypes());
1920
        theTypes.add(this.getDefaultFeatureType());
1921
        for( int n=0; n<theTypes.size(); n++ ) {
1922
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1923
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1924
            if(x!=null && !x.isEmpty()) {
1925
                for (FeatureAttributeDescriptor attrdesc : x) {
1926
                    if (type.get(attrdesc.getName())==null) {
1927
                        type.add(attrdesc);
1928
                    }
1929
                }
1930
            }
1931
        }
1932
        
1933
    }
1934
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
1935
        // FIXME: Falta por implementar
1936
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
1937
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
1938
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
1939
//                if (attributeDescriptor.isComputed()) {
1940
//                    target.remove(attributeDescriptor.getName());
1941
//                }
1942
//            }
1943
//        }
1944
        return ftypes;
1945
    }
1946
    
1947

    
1948
    private void saveDALFile() {       
1949
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1950
        try {
1951
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1952
            if( resourcesStorage == null || resourcesStorage.isReadOnly() ) {
1953
                return;
1954
            }
1955
            resource = resourcesStorage.getResource("dal");
1956
            if( resource == null || resource.isReadOnly() ) {
1957
                return;
1958
            }
1959
            DALFile dalFile = DALFile.getDALFile();
1960
            dalFile.setStore(this);
1961
            if( !dalFile.isEmpty() ) {
1962
                dalFile.write(resource);
1963
            }
1964
        } catch (Throwable ex) {
1965
            LOGGER.warn("Can't save DAL resource", ex);
1966
        } finally {
1967
            IOUtils.closeQuietly(resource);
1968
        }
1969
    }
1970
    
1971
    private void loadDALFile() {
1972
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1973
        try {
1974
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1975
            if( resourcesStorage == null ) {
1976
                return;
1977
            }
1978
            resource = resourcesStorage.getResource("dal");
1979
            if( resource == null || !resource.exists() ) {
1980
                return;
1981
            }
1982
            DALFile dalFile = DALFile.getDALFile(resource);
1983
            if( !dalFile.isEmpty() ) {
1984
                dalFile.updateStore(this);
1985
            }
1986
        } catch (Throwable ex) {
1987
            LOGGER.warn("Can't load DAL resource", ex);
1988
        } finally {
1989
            IOUtils.closeQuietly(resource);
1990
        }
1991
    }
1992
    
1993
    /**
1994
     * Save changes in the provider without leaving the edit mode.
1995
     * Do not call observers to communicate a change of ediding mode.
1996
     * The operation's history is eliminated to prevent inconsistencies
1997
     * in the data.
1998
     *
1999
     * @throws DataException
2000
     */
2001
    @Override
2002
    synchronized public void commitChanges() throws DataException {
2003
      LOGGER.debug("commitChanges of mode: {}", mode);
2004
      if( !canCommitChanges() ) {
2005
              throw new WriteNotAllowedException(getName());
2006
      }
2007
      try {
2008
        switch (mode) {
2009
        case MODE_QUERY:
2010
          throw new NeedEditingModeException(this.getName());
2011

    
2012
        case MODE_APPEND:
2013
          this.provider.endAppend();
2014
          exitEditingMode();
2015
          invalidateIndexes();
2016
          this.provider.beginAppend();
2017
          hasInserts = false;
2018
          break;
2019

    
2020
        case MODE_FULLEDIT:
2021
          if (hasStrongChanges && !this.allowWrite()) {
2022
            throw new WriteNotAllowedException(getName());
2023
          }
2024
          if (hasStrongChanges) {
2025
            validateFeatures(Feature.FINISH_EDITING);
2026
            provider.performChanges(featureManager.getDeleted(),
2027
              featureManager.getInserted(),
2028
              featureManager.getUpdated(),
2029
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2030
          }
2031
          invalidateIndexes();
2032
          featureManager = new FeatureManager(this);
2033
          featureTypeManager = new FeatureTypeManager(this);
2034
          spatialManager = new SpatialManager(this, provider.getEnvelope());
2035

    
2036
          commands =
2037
            new DefaultFeatureCommandsStack(this, featureManager,
2038
              spatialManager, featureTypeManager);
2039
          featureCount = null;
2040
          hasStrongChanges = false;
2041
          hasInserts = false;
2042
          break;
2043
        }
2044
      } catch (Exception e) {
2045
        throw new FinishEditingException(e);
2046
      }
2047
    }
2048

    
2049
    @Override
2050
    synchronized public boolean canCommitChanges() throws DataException {
2051
        if ( !this.allowWrite()) {
2052
                return false;
2053
        }
2054
            switch (mode) {
2055
            default:
2056
        case MODE_QUERY:
2057
                return false;
2058

    
2059
        case MODE_APPEND:
2060
                return true;
2061

    
2062
        case MODE_FULLEDIT:
2063
            List types = this.getFeatureTypes();
2064
            for( int i=0; i<types.size(); i++ ) {
2065
                    Object type = types.get(i);
2066
                    if( type instanceof DefaultEditableFeatureType ) {
2067
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
2068
                                    return false;
2069
                            }
2070
                    }
2071
            }
2072
            return true;
2073
            }
2074
    }
2075

    
2076
    @Override
2077
    public void beginEditingGroup(String description)
2078
        throws NeedEditingModeException {
2079
        checkInEditingMode();
2080
        commands.startComplex(description);
2081
    }
2082

    
2083
    @Override
2084
    public void endEditingGroup() throws NeedEditingModeException {
2085
        checkInEditingMode();
2086
        commands.endComplex();
2087
    }
2088

    
2089
    @Override
2090
    public boolean isAppendModeSupported() {
2091
        return this.provider.supportsAppendMode();
2092
    }
2093

    
2094
    @Override
2095
    public void export(DataServerExplorer explorer, String provider,
2096
        NewFeatureStoreParameters params, String name) throws DataException {
2097

    
2098
        if (this.getFeatureTypes().size() != 1) {
2099
            throw new NotYetImplemented(
2100
                "export whith more than one type not yet implemented");
2101
        }
2102
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2103
        FeatureStore target = null;
2104
        FeatureSet features = null;
2105
        DisposableIterator iterator = null;
2106
        try {
2107
            FeatureType type = this.getDefaultFeatureType();
2108
            if ((params.getDefaultFeatureType() == null)
2109
                || (params.getDefaultFeatureType().size() == 0)) {
2110
                params.setDefaultFeatureType(type.getEditable());
2111

    
2112
            }
2113
            explorer.add(provider, params, true);
2114
            DataManager manager = DALLocator.getDataManager();
2115
            
2116
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2117
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2118

    
2119
            target = (FeatureStore) manager.openStore(provider, openParams);
2120
            FeatureType targetType = target.getDefaultFeatureType();
2121

    
2122
            target.edit(MODE_APPEND);
2123
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2124
            if (featureSelection.getSize() > 0) {
2125
                features = this.getFeatureSelection();
2126
            } else {
2127
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2128
                    FeatureQuery query = createFeatureQuery();
2129
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2130
                        query.getOrder().add(pkattr.getName(), true);
2131
                    }
2132
                    features = this.getFeatureSet(query);
2133
                } else {
2134
                    features = this.getFeatureSet();
2135
                }
2136
            }
2137
            iterator = features.fastIterator();
2138
            while (iterator.hasNext()) {
2139
                DefaultFeature feature = (DefaultFeature) iterator.next();
2140
                target.insert(target.createNewFeature(targetType, feature));
2141
            }
2142
            target.finishEditing();
2143
            target.dispose();
2144
        } catch (Exception e) {
2145
            throw new DataExportException(e, params.toString());
2146
        } finally {
2147
            dispose(iterator);
2148
            dispose(features);
2149
            dispose(target);
2150
        }
2151
    }
2152

    
2153
    @Override
2154
    public void copyTo(final FeatureStore target) {
2155
        boolean finishEditingAtEnd = false;
2156
        try {
2157
            if( !target.isEditing() && !target.isAppending() ) {
2158
                finishEditingAtEnd = true;
2159
                target.edit(MODE_APPEND);
2160
            }
2161
            this.accept((Object obj) -> {
2162
                Feature f_src = (Feature) obj;
2163
                EditableFeature f_dst = target.createNewFeature(f_src);
2164
                target.insert(f_dst);
2165
            });
2166
            if( finishEditingAtEnd ) {
2167
                target.finishEditing();
2168
            }
2169
            
2170
        } catch(Exception ex) {
2171
            try {
2172
                if( finishEditingAtEnd ) {
2173
                    target.cancelEditing();
2174
                }
2175
            } catch (Exception ex1) {
2176
            }
2177
            throw new RuntimeException("Can't copy store.",ex);
2178
        }
2179
            
2180
    }
2181
    
2182
    //
2183
    // ====================================================================
2184
    // Obtencion de datos
2185
    // getDataCollection, getFeatureCollection
2186
    //
2187

    
2188
    @Override
2189
    public DataSet getDataSet() throws DataException {
2190
        checkNotInAppendMode();
2191
        FeatureQuery query =
2192
            new DefaultFeatureQuery(this.getDefaultFeatureType());
2193
        return new DefaultFeatureSet(this, query);
2194
    }
2195

    
2196
    @Override
2197
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2198
        checkNotInAppendMode();
2199
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2200
    }
2201

    
2202
    @Override
2203
    public void getDataSet(Observer observer) throws DataException {
2204
        checkNotInAppendMode();
2205
        this.getFeatureSet(null, observer);
2206
    }
2207

    
2208
    @Override
2209
    public void getDataSet(DataQuery dataQuery, Observer observer)
2210
        throws DataException {
2211
        checkNotInAppendMode();
2212
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2213
    }
2214

    
2215
    @Override
2216
    public FeatureSet getFeatureSet() throws DataException {
2217
        return this.getFeatureSet((FeatureQuery)null);
2218
    }
2219

    
2220
    @Override
2221
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2222
        throws DataException {
2223
        checkNotInAppendMode();
2224
        if( featureQuery==null ) {
2225
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2226
        }
2227
        return new DefaultFeatureSet(this, featureQuery);
2228
    }
2229

    
2230
    @Override
2231
    public FeatureSet getFeatureSet(String filter) throws DataException {
2232
        return this.getFeatureSet(filter, null, true);
2233
    }
2234

    
2235
    @Override
2236
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2237
        return this.getFeatureSet(filter, sortBy, true);
2238
    }
2239

    
2240
    @Override
2241
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2242
        return this.getFeatureSet(filter, null, true);
2243
    }
2244
    
2245
    @Override
2246
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2247
        return this.getFeatureSet(filter, sortBy, true);
2248
    }
2249

    
2250
    @Override
2251
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2252
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2253
        return this.getFeatureSet(query);
2254
    }
2255
    
2256
    @Override
2257
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2258
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2259
        return this.getFeatureSet(query);
2260
    }
2261
    
2262
    @Override
2263
    public List<Feature> getFeatures(String filter)  {
2264
        return this.getFeatures(filter, null, true);
2265
    }
2266

    
2267
    @Override
2268
    public List<Feature> getFeatures(String filter, String sortBy)  {
2269
        return this.getFeatures(filter, sortBy, true);
2270
    }
2271

    
2272
    @Override
2273
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
2274
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2275
        return this.getFeatures(query, 0);
2276
    }
2277
    
2278
    @Override
2279
    public List<Feature> getFeatures(Expression filter)  {
2280
        return this.getFeatures(filter, null, true);
2281
    }
2282

    
2283
    @Override
2284
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
2285
        return this.getFeatures(filter, sortBy, true);
2286
    }
2287

    
2288
    @Override
2289
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
2290
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2291
        return this.getFeatures(query, 0);
2292
    }
2293
    
2294
    @Override
2295
    public List<Feature> getFeatures(FeatureQuery query)  {
2296
        return this.getFeatures(query, 0);
2297
    }
2298
    
2299
    @Override
2300
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
2301
        try {
2302
            if( pageSize<=0 ) {
2303
                pageSize = 100;
2304
            }
2305
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2306
            return pager.asList();
2307
        } catch (BaseException ex) {
2308
            throw new RuntimeException("Can't create the list of features.", ex);
2309
        }
2310
    }
2311

    
2312
    @Override
2313
    public List<Feature> getFeatures() {
2314
        return this.getFeatures(null, 0);
2315
    }
2316

    
2317
    @Override
2318
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2319
        return this.getFeatures64(null, 0);
2320
    }
2321

    
2322
    @Override
2323
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2324
        return this.getFeatures64(filter, null, true);
2325
    }
2326
    
2327
    @Override
2328
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc)  {
2329
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2330
        return this.getFeatures64(query, 0);
2331
    }
2332

    
2333
    @Override
2334
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize)  {
2335
        try {
2336
            if( pageSize<=0 ) {
2337
                pageSize = 100;
2338
            }
2339
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2340
            return pager;
2341
        } catch (BaseException ex) {
2342
            throw new RuntimeException("Can't create the list of features.", ex);
2343
        }
2344
    }
2345

    
2346
    @Override
2347
    public Feature first() throws DataException {
2348
        return this.findFirst((FeatureQuery)null);
2349
    }
2350
    
2351
    @Override
2352
    public Feature findFirst(String filter) throws DataException {
2353
        return this.findFirst(filter, (String)null, true);
2354
    }
2355

    
2356
    @Override
2357
    public Feature findFirst(String filter, String sortBy) throws DataException {
2358
        return this.findFirst(filter, sortBy, true);
2359
    }
2360

    
2361
    @Override
2362
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2363
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2364
        return findFirst(query);
2365
    }
2366

    
2367
    @Override
2368
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2369
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2370
        return findFirst(query);
2371
    }
2372
    
2373
    @Override
2374
    public Feature findFirst(Expression filter) throws DataException {
2375
        return this.findFirst(filter, (String)null, true);
2376
    }
2377

    
2378
    @Override
2379
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2380
        return this.findFirst(filter, sortBy, true);
2381
    }
2382

    
2383
    @Override
2384
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2385
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2386
        return findFirst(query);
2387
    }
2388
    
2389
    @Override
2390
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2391
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2392
        return findFirst(query);
2393
    }
2394
    
2395
    @Override
2396
    public Feature findFirst(FeatureQuery query) throws DataException {
2397
        if( query == null ) {
2398
            query = this.createFeatureQuery();
2399
        } else {
2400
            query = query.getCopy();
2401
        }
2402
        query.setLimit(1);
2403
        final MutableObject<Feature> feature = new MutableObject<>();
2404
        try {
2405
            this.accept((Object obj) -> {
2406
                feature.setValue((Feature) obj);
2407
                throw new VisitCanceledException();
2408
            }, query);
2409
        } catch(VisitCanceledException ex) {
2410

    
2411
        } catch(DataException ex) {
2412
            throw ex;
2413
        } catch(Exception ex) {
2414
            throw new RuntimeException("", ex);
2415
        }
2416
        return feature.getValue();
2417
    }
2418

    
2419
    @Override
2420
    public void accept(Visitor visitor) throws BaseException {
2421
        this.accept(visitor, null);
2422
    }
2423

    
2424
    @Override
2425
    public void accept(Visitor visitor, DataQuery dataQuery)
2426
        throws BaseException {
2427
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2428
        try {
2429
            set.accept(visitor);
2430
        } finally {
2431
            set.dispose();
2432
        }
2433
    }
2434

    
2435
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2436
        throws DataException {
2437
        DefaultFeatureType fType =
2438
            (DefaultFeatureType) this.getFeatureType(featureQuery
2439
                .getFeatureTypeId());
2440
        if( featureQuery.hasAttributeNames() || 
2441
            featureQuery.hasConstantsAttributeNames() ||
2442
            fType.hasRequiredFields()    
2443
            ) {
2444
            if( featureQuery.hasGroupByColumns()) {
2445
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2446
            } else {
2447
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2448
            }
2449
        }
2450
        return fType;
2451
    }
2452

    
2453
    @Override
2454
    public void getFeatureSet(Observer observer) throws DataException {
2455
        checkNotInAppendMode();
2456
        this.getFeatureSet(null, observer);
2457
    }
2458

    
2459
    @Override
2460
    public void getFeatureSet(FeatureQuery query, Observer observer)
2461
        throws DataException {
2462
        class LoadInBackGround implements Runnable {
2463

    
2464
            private final FeatureStore store;
2465
            private final FeatureQuery query;
2466
            private final Observer observer;
2467

    
2468
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2469
                Observer observer) {
2470
                this.store = store;
2471
                this.query = query;
2472
                this.observer = observer;
2473
            }
2474

    
2475
            void notify(FeatureStoreNotification theNotification) {
2476
                observer.update(store, theNotification);
2477
            }
2478

    
2479
            @Override
2480
            public void run() {
2481
                FeatureSet set = null;
2482
                try {
2483
                    set = store.getFeatureSet(query);
2484
                    notify(new DefaultFeatureStoreNotification(store,
2485
                        FeatureStoreNotification.LOAD_FINISHED, set));
2486
                } catch (Exception e) {
2487
                    notify(new DefaultFeatureStoreNotification(store,
2488
                        FeatureStoreNotification.LOAD_FINISHED, e));
2489
                } finally {
2490
                    dispose(set);
2491
                }
2492
            }
2493
        }
2494

    
2495
        checkNotInAppendMode();
2496
        if (query == null) {
2497
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2498
        }
2499
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2500
        Thread thread = new Thread(task, "Load Feature Set in background");
2501
        thread.start();
2502
    }
2503

    
2504
    @Override
2505
    public Feature getFeatureByReference(FeatureReference reference)
2506
        throws DataException {
2507
        checkNotInAppendMode();
2508
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2509
        FeatureType featureType;
2510
        if (ref.getFeatureTypeId() == null) {
2511
            featureType = this.getDefaultFeatureType();
2512
        } else {
2513
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2514
        }
2515
        return this.getFeatureByReference(reference, featureType);
2516
    }
2517

    
2518
    @Override
2519
    public Feature getFeatureByReference(FeatureReference reference,
2520
        FeatureType featureType) throws DataException {
2521
        checkNotInAppendMode();
2522
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2523
        if (this.mode == MODE_FULLEDIT) {
2524
            Feature f = featureManager.get(reference, this, featureType);
2525
            if (f != null) {
2526
                return f;
2527
            }
2528
        }
2529

    
2530
        FeatureType sourceFeatureType = featureType;
2531
        if (!this.transforms.isEmpty()) {
2532
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2533
        }
2534
        // TODO comprobar que el id es de este store
2535

    
2536
        DefaultFeature feature =
2537
            new DefaultFeature(this,
2538
                this.provider.getFeatureProviderByReference(
2539
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2540

    
2541
        if (!this.transforms.isEmpty()) {
2542
            return this.transforms.applyTransform(feature, featureType);
2543
        }
2544
        return feature;
2545
    }
2546

    
2547
    //
2548
    // ====================================================================
2549
    // Gestion de features
2550
    //
2551

    
2552
    private FeatureType fixFeatureType(DefaultFeatureType type)
2553
        throws DataException {
2554
        FeatureType original = this.getDefaultFeatureType();
2555

    
2556
        if ((type == null) || type.equals(original)) {
2557
            return original;
2558
        } else {
2559
            if (!type.isSubtypeOf(original)) {
2560
                Iterator iter = this.getFeatureTypes().iterator();
2561
                FeatureType tmpType;
2562
                boolean found = false;
2563
                while (iter.hasNext()) {
2564
                    tmpType = (FeatureType) iter.next();
2565
                    if (type.equals(tmpType)) {
2566
                        return type;
2567

    
2568
                    } else
2569
                        if (type.isSubtypeOf(tmpType)) {
2570
                            found = true;
2571
                            original = tmpType;
2572
                            break;
2573
                        }
2574

    
2575
                }
2576
                if (!found) {
2577
                    throw new IllegalFeatureTypeException(getName());
2578
                }
2579
            }
2580
        }
2581

    
2582
        // Checks that type has all fields of pk
2583
        // else add the missing attributes at the end.
2584
        if (!original.hasOID()) {
2585
            // Gets original pk attributes
2586
            DefaultEditableFeatureType edOriginal =
2587
                (DefaultEditableFeatureType) original.getEditable();
2588
            FeatureAttributeDescriptor orgAttr;
2589
            Iterator edOriginalIter = edOriginal.iterator();
2590
            while (edOriginalIter.hasNext()) {
2591
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2592
                if (!orgAttr.isPrimaryKey()) {
2593
                    edOriginalIter.remove();
2594
                }
2595
            }
2596

    
2597
            // Checks if all pk attributes are in type
2598
            Iterator typeIterator;
2599
            edOriginalIter = edOriginal.iterator();
2600
            FeatureAttributeDescriptor attr;
2601
            while (edOriginalIter.hasNext()) {
2602
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2603
                typeIterator = type.iterator();
2604
                while (typeIterator.hasNext()) {
2605
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2606
                    if (attr.getName().equals(orgAttr.getName())) {
2607
                        edOriginalIter.remove();
2608
                        break;
2609
                    }
2610
                }
2611
            }
2612

    
2613
            // add missing pk attributes if any
2614
            if (edOriginal.size() > 0) {
2615
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2616
                DefaultEditableFeatureType edType =
2617
                    (DefaultEditableFeatureType) original.getEditable();
2618
                edType.clear();
2619
                edType.addAll(type);
2620
                edType.addAll(edOriginal);
2621
                if (!isEditable) {
2622
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2623
                }
2624
            }
2625

    
2626
        }
2627

    
2628
        return type;
2629
    }
2630

    
2631
    @Override
2632
    public void validateFeatures(int mode) throws DataException {
2633
        FeatureSet collection = null;
2634
        DisposableIterator iter = null;
2635
        try {
2636
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2637
            if( rules==null || rules.isEmpty() ) {
2638
                return;
2639
            }
2640
            checkNotInAppendMode();
2641
            collection = this.getFeatureSet();
2642
            iter = collection.fastIterator();
2643
            long previousVersionOfUpdate = currentVersionOfUpdate();
2644
            while (iter.hasNext()) {
2645
                ((DefaultFeature) iter.next()).validate(mode);
2646
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2647
                    throw new ConcurrentDataModificationException(getName());
2648
                }
2649
            }
2650
        } catch (Exception e) {
2651
            throw new ValidateFeaturesException(e, getName());
2652
        } finally {
2653
            DisposeUtils.disposeQuietly(iter);
2654
            DisposeUtils.disposeQuietly(collection);
2655
        }
2656
    }
2657

    
2658
    @Override
2659
    public FeatureType getDefaultFeatureType() throws DataException {
2660
        try {
2661

    
2662
            if (isEditing()) {
2663
                FeatureType auxFeatureType =
2664
                    featureTypeManager.getType(defaultFeatureType.getId());
2665
                if (auxFeatureType != null) {
2666
                    return avoidEditable(auxFeatureType);
2667
                }
2668
            }
2669
            FeatureType type = this.transforms.getDefaultFeatureType();
2670
                if (type != null) {
2671
                return avoidEditable(type);
2672
                }
2673

    
2674
            return avoidEditable(defaultFeatureType);
2675

    
2676
        } catch (Exception e) {
2677
            throw new GetFeatureTypeException(e, getName());
2678
        }
2679
    }
2680

    
2681
    @Override
2682
    public FeatureType getDefaultFeatureTypeQuietly() {
2683
      try {
2684
        return this.getDefaultFeatureType();
2685
      } catch(Exception ex) {
2686
        return null;
2687
      }
2688
    }
2689
    
2690
    private FeatureType avoidEditable(FeatureType ft) {
2691
        if (ft instanceof EditableFeatureType) {
2692
            return ((EditableFeatureType) ft).getNotEditableCopy();
2693
        } else {
2694
            return ft;
2695
        }
2696
    }
2697

    
2698
    @Override
2699
    public FeatureType getFeatureType(String featureTypeId)
2700
        throws DataException {
2701
        if (featureTypeId == null) {
2702
            return this.getDefaultFeatureType();
2703
        }
2704
        try {
2705
            if (isEditing()) {
2706
                FeatureType auxFeatureType =
2707
                    featureTypeManager.getType(featureTypeId);
2708
                if (auxFeatureType != null) {
2709
                    return auxFeatureType;
2710
                }
2711
            }
2712
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2713
            if (type != null) {
2714
                return type;
2715
            }
2716
            Iterator iter = this.featureTypes.iterator();
2717
            while (iter.hasNext()) {
2718
                type = (FeatureType) iter.next();
2719
                if (type.getId().equals(featureTypeId)) {
2720
                    return type;
2721
                }
2722
            }
2723
            return null;
2724
        } catch (Exception e) {
2725
            throw new GetFeatureTypeException(e, getName());
2726
        }
2727
    }
2728

    
2729
    public FeatureType getProviderDefaultFeatureType() {
2730
        return defaultFeatureType;
2731
    }
2732

    
2733
    @Override
2734
    public List getFeatureTypes() throws DataException {
2735
        try {
2736
            List types;
2737
            if (isEditing()) {
2738
                types = new ArrayList();
2739
                for (FeatureType type : featureTypes) {
2740
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2741
                    if (typeaux != null) {
2742
                        types.add(typeaux);
2743
                    } else {
2744
                        types.add(type);
2745
                    }
2746
                }
2747
                Iterator it = featureTypeManager.newsIterator();
2748
                while (it.hasNext()) {
2749
                    FeatureType type = (FeatureType) it.next();
2750
                    types.add(type);
2751
                }
2752
            } else {
2753
                types = this.transforms.getFeatureTypes();
2754
                if (types == null) {
2755
                    types = featureTypes;
2756
                }
2757
            }
2758
            return Collections.unmodifiableList(types);
2759
        } catch (Exception e) {
2760
            throw new GetFeatureTypeException(e, getName());
2761
        }
2762
    }
2763

    
2764
    public List getProviderFeatureTypes() throws DataException {
2765
        return Collections.unmodifiableList(this.featureTypes);
2766
    }
2767

    
2768
    @Override
2769
    public Feature createFeature(FeatureProvider data) throws DataException {
2770
        DefaultFeature feature = new DefaultFeature(this, data);
2771
        return feature;
2772
    }
2773

    
2774
    public Feature createFeature(FeatureProvider data, FeatureType type)
2775
        throws DataException {
2776
        // FIXME: falta por implementar
2777
        // Comprobar si es un subtipo del feature de data
2778
        // y construir un feature usando el subtipo.
2779
        // Probablemente requiera generar una copia del data.
2780
        throw new NotYetImplemented();
2781
    }
2782

    
2783
    @Override
2784
    public EditableFeature createNewFeature(FeatureType type,
2785
        Feature defaultValues) throws DataException {
2786
        try {
2787
            FeatureProvider data = createNewFeatureProvider(type);
2788
            DefaultEditableFeature feature =
2789
                new DefaultEditableFeature(this, data);
2790
            feature.initializeValues(defaultValues);
2791
            data.setNew(true);
2792

    
2793
            return feature;
2794
        } catch (Exception e) {
2795
            throw new CreateFeatureException(e, getName());
2796
        }
2797
    }
2798

    
2799
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2800
        throws DataException {
2801
        type = this.fixFeatureType((DefaultFeatureType) type);
2802
        FeatureProvider data = this.provider.createFeatureProvider(type);
2803
        data.setNew(true);
2804
        if (type.hasOID() && (data.getOID() == null)) {
2805
            data.setOID(this.provider.createNewOID());
2806
        } else {
2807
            data.setOID(this.getTemporalOID());
2808
        }
2809
        return data;
2810

    
2811
    }
2812

    
2813
    @Override
2814
    public EditableFeature createNewFeature(FeatureType type,
2815
        boolean defaultValues) throws DataException {
2816
        try {
2817
            FeatureProvider data = createNewFeatureProvider(type);
2818
            DefaultEditableFeature feature =
2819
                new DefaultEditableFeature(this, data);
2820
            if (defaultValues) {
2821
                feature.initializeValues();
2822
            }
2823
            return feature;
2824
        } catch (Exception e) {
2825
            throw new CreateFeatureException(e, getName());
2826
        }
2827
    }
2828

    
2829
    @Override
2830
    public EditableFeature createNewFeature(boolean defaultValues)
2831
        throws DataException {
2832
        return this.createNewFeature(this.getDefaultFeatureType(),
2833
            defaultValues);
2834
    }
2835

    
2836
    @Override
2837
    public EditableFeature createNewFeature() throws DataException {
2838
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2839
    }
2840

    
2841
    @Override
2842
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2843
        FeatureType ft = this.getDefaultFeatureType();
2844
        EditableFeature f = this.createNewFeature(ft, false);
2845
        f.copyFrom(defaultValues);
2846
        return f;
2847
    }
2848

    
2849
    @Override
2850
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2851
        FeatureType ft = this.getDefaultFeatureType();
2852
        EditableFeature f = this.createNewFeature(ft, false);
2853
        f.copyFrom(defaultValues);
2854
        return f;
2855
    }
2856

    
2857
    @Override
2858
    public EditableFeatureType createFeatureType() {
2859
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2860
        return ftype;
2861
    }
2862

    
2863
    @Override
2864
    public EditableFeatureType createFeatureType(String id) {
2865
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2866
        return ftype;
2867
    }
2868

    
2869
    //
2870
    // ====================================================================
2871
    // Index related methods
2872
    //
2873

    
2874
    @Override
2875
    public FeatureIndexes getIndexes() {
2876
        return this.indexes;
2877
    }
2878

    
2879
    @Override
2880
    public FeatureIndex createIndex(FeatureType featureType,
2881
        String attributeName, String indexName) throws DataException {
2882
        return createIndex(null, featureType, attributeName, indexName);
2883
    }
2884

    
2885
    @Override
2886
    public FeatureIndex createIndex(String indexTypeName,
2887
        FeatureType featureType, String attributeName, String indexName)
2888
        throws DataException {
2889

    
2890
        return createIndex(indexTypeName, featureType, attributeName,
2891
            indexName, false, null);
2892
    }
2893

    
2894
    @Override
2895
    public FeatureIndex createIndex(FeatureType featureType,
2896
        String attributeName, String indexName, Observer observer)
2897
        throws DataException {
2898
        return createIndex(null, featureType, attributeName, indexName,
2899
            observer);
2900
    }
2901

    
2902
    @Override
2903
    public FeatureIndex createIndex(String indexTypeName,
2904
        FeatureType featureType, String attributeName, String indexName,
2905
        final Observer observer) throws DataException {
2906

    
2907
        return createIndex(indexTypeName, featureType, attributeName,
2908
            indexName, true, observer);
2909
    }
2910

    
2911
    private FeatureIndex createIndex(String indexTypeName,
2912
        FeatureType featureType, String attributeName, String indexName,
2913
        boolean background, final Observer observer) throws DataException {
2914

    
2915
        checkNotInAppendMode();
2916
        FeatureIndexProviderServices index;
2917
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2918
                featureType, indexName,
2919
                featureType.getAttributeDescriptor(attributeName));
2920

    
2921
        try {
2922
            index.fill(background, observer);
2923
        } catch (FeatureIndexException e) {
2924
            throw new InitializeException(index.getName(), e);
2925
        }
2926

    
2927
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2928
        return index;
2929
    }
2930

    
2931
    //
2932
    // ====================================================================
2933
    // Transforms related methods
2934
    //
2935

    
2936
    @Override
2937
    public FeatureStoreTransforms getTransforms() {
2938
        return this.transforms;
2939
    }
2940

    
2941
    @Override
2942
    public FeatureQuery createFeatureQuery() {
2943
        return new DefaultFeatureQuery();
2944
    }
2945
    
2946
    @Override
2947
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
2948
        FeatureQuery query = null;
2949
        if( filter!=null ) {
2950
            query = this.createFeatureQuery();
2951
            query.setFilter(filter);
2952
        }
2953
        if( !StringUtils.isBlank(sortBy) ) {
2954
            if( query == null ) {
2955
                query = this.createFeatureQuery();
2956
            }
2957
            if ( StringUtils.containsAny(sortBy, "(", ")") ) {
2958
                throw new IllegalArgumentException("Incorrect sortBy expression");
2959
            }
2960
            String[] attrnames;
2961
            if( sortBy.contains(",") ) {
2962
                attrnames = StringUtils.split(sortBy, ",");
2963
            } else {
2964
                attrnames = new String[] { sortBy };
2965
            }
2966
            for (String attrname : attrnames) {
2967
                attrname = attrname.trim();
2968
                if( attrname.startsWith("-") ) {
2969
                    query.getOrder().add(attrname.substring(1).trim(), false);
2970
                } else if( attrname.endsWith("-") ) { 
2971
                    query.getOrder().add(attrname.substring(0,sortBy.length()-1).trim(), false);
2972
                } else if( attrname.startsWith("+") ) {
2973
                    query.getOrder().add(attrname.substring(1).trim(), true);
2974
                } else if( attrname.endsWith("-") ) { 
2975
                    query.getOrder().add(attrname.substring(0,sortBy.length()-1).trim(), true);
2976
                } else {
2977
                    query.getOrder().add(attrname, asc);
2978
                }
2979
            }
2980
        }
2981
        if( query != null ) {
2982
            query.retrievesAllAttributes();
2983
        }
2984
        return query;
2985
    }
2986
    
2987
    @Override
2988
    public FeatureQuery createFeatureQuery(String filter) {
2989
        return this.createFeatureQuery(
2990
                ExpressionUtils.createExpression(filter), 
2991
                (String)null, 
2992
                true
2993
        );
2994
    }
2995
    
2996
    @Override
2997
    public FeatureQuery createFeatureQuery(Expression filter) {
2998
        return this.createFeatureQuery(
2999
                filter, 
3000
                (String)null, 
3001
                true
3002
        );
3003
    }
3004
    
3005
    @Override
3006
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
3007
        if( StringUtils.isBlank(filter) ) {
3008
            return this.createFeatureQuery(
3009
                    (Expression)null, 
3010
                    sortBy, 
3011
                    asc
3012
            );
3013
        } else {
3014
            return this.createFeatureQuery(
3015
                    ExpressionUtils.createExpression(filter), 
3016
                    sortBy, 
3017
                    asc
3018
            );
3019
        }
3020
    }
3021
    
3022
    @Override
3023
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
3024
        FeatureQuery query = null;
3025
        if( filter != null ) {
3026
            query = this.createFeatureQuery();
3027
            query.setFilter(filter);
3028
        }
3029
        if( sortBy !=  null) {
3030
            if( query == null ) {
3031
                query = this.createFeatureQuery();
3032
            }
3033
            query.getOrder().add(sortBy, asc);
3034
        }
3035
        
3036
        if( query != null ) {
3037
            query.retrievesAllAttributes();
3038
        }
3039
        return query;
3040
    }
3041
    
3042
    @Override
3043
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
3044
        if( StringUtils.isBlank(filter) ) {
3045
            return this.createFeatureQuery(
3046
                    (Expression)null, 
3047
                    sortBy, 
3048
                    asc
3049
            );
3050
        } else {
3051
            return this.createFeatureQuery(
3052
                    ExpressionUtils.createExpression(filter), 
3053
                    sortBy, 
3054
                    asc
3055
            );
3056
        }
3057
    }
3058
    
3059
    @Override
3060
    public DataQuery createQuery() {
3061
        return createFeatureQuery();
3062
    }
3063

    
3064
    //
3065
    // ====================================================================
3066
    // UndoRedo related methods
3067
    //
3068

    
3069
    @Override
3070
    public boolean canRedo() {
3071
        return commands.canRedo();
3072
    }
3073

    
3074
    @Override
3075
    public boolean canUndo() {
3076
        return commands.canUndo();
3077
    }
3078

    
3079
    @Override
3080
    public void redo(int num) throws RedoException {
3081
        for (int i = 0; i < num; i++) {
3082
            redo();
3083
        }
3084
    }
3085

    
3086
    @Override
3087
    public void undo(int num) throws UndoException {
3088
        for (int i = 0; i < num; i++) {
3089
            undo();
3090
        }
3091
    }
3092

    
3093
    //
3094
    // ====================================================================
3095
    // Metadata related methods
3096
    //
3097

    
3098
    @Override
3099
    public Object getMetadataID() {
3100
        return this.provider.getSourceId();
3101
    }
3102

    
3103
    @Override
3104
    public void delegate(DynObject dynObject) {
3105
        this.metadata.delegate(dynObject);
3106
    }
3107

    
3108
    @Override
3109
    public DynClass getDynClass() {
3110
        return this.metadata.getDynClass();
3111
    }
3112

    
3113
    @Override
3114
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3115
        try {
3116
            if (this.transforms.hasDynValue(name)) {
3117
                return this.transforms.getDynValue(name);
3118
            }
3119
            if (this.metadata.hasDynValue(name)) {
3120
                return this.metadata.getDynValue(name);
3121
            }
3122
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3123
                return this.provider.getProviderName();
3124
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3125
                return this.provider.getSourceId();
3126
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3127
                try {
3128
                    return this.getDefaultFeatureType();
3129
                } catch (DataException e) {
3130
                    return null;
3131
                }
3132
            }
3133
            return this.metadata.getDynValue(name);
3134
        } catch(Exception ex ) {
3135
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
3136
            return null;
3137
        }
3138
    }
3139

    
3140
    @Override
3141
    public boolean hasDynValue(String name) {
3142
        if (this.transforms.hasDynValue(name)) {
3143
            return true;
3144
        }
3145
        return this.metadata.hasDynValue(name);
3146
    }
3147

    
3148
    @Override
3149
    public boolean hasDynMethod(String name) {
3150
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
3151
    }
3152

    
3153
    @Override
3154
    public void implement(DynClass dynClass) {
3155
        this.metadata.implement(dynClass);
3156
    }
3157

    
3158
    @Override
3159
    public Object invokeDynMethod(String name, Object[] args)
3160
        throws DynMethodException {
3161
        return this.metadata.invokeDynMethod(this, name, args);
3162
    }
3163

    
3164
    @Override
3165
    public Object invokeDynMethod(int code, Object[] args)
3166
        throws DynMethodException {
3167
        return this.metadata.invokeDynMethod(this, code, args);
3168
    }
3169

    
3170
    @Override
3171
    public void setDynValue(String name, Object value)
3172
        throws DynFieldNotFoundException {
3173
                if( this.transforms.hasDynValue(name) ) {
3174
                        this.transforms.setDynValue(name, value);
3175
                        return;
3176
                }
3177
        this.metadata.setDynValue(name, value);
3178

    
3179
    }
3180

    
3181
    /*
3182
     * (non-Javadoc)
3183
     *
3184
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3185
     */
3186
    @Override
3187
    public Set getMetadataChildren() {
3188
        return this.metadataChildren;
3189
    }
3190

    
3191
    /*
3192
     * (non-Javadoc)
3193
     *
3194
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3195
     */
3196
    @Override
3197
    public String getMetadataName() {
3198
        return this.provider.getProviderName();
3199
    }
3200

    
3201
    public FeatureTypeManager getFeatureTypeManager() {
3202
        return this.featureTypeManager;
3203
    }
3204

    
3205
    @Override
3206
    public long getFeatureCount() throws DataException {
3207
        if (featureCount == null) {
3208
            featureCount = this.provider.getFeatureCount();
3209
        }
3210
        if (this.isEditing()) {
3211
            if(this.isAppending()) {
3212
                try{
3213
                    throw new IllegalStateException();
3214
                } catch(IllegalStateException e) {
3215
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
3216
                }
3217
                return -1;
3218
            } else {
3219
                return featureCount
3220
                    + this.featureManager.getDeltaSize();
3221
            }
3222
        }
3223
        return featureCount;
3224
    }
3225

    
3226
    private Long getTemporalOID() {
3227
        return this.temporalOid++;
3228
    }
3229

    
3230
    @Override
3231
    public FeatureType getProviderFeatureType(String featureTypeId) {
3232
        if (featureTypeId == null) {
3233
            return this.defaultFeatureType;
3234
        }
3235
        FeatureType type;
3236
        Iterator iter = this.featureTypes.iterator();
3237
        while (iter.hasNext()) {
3238
            type = (FeatureType) iter.next();
3239
            if (type.getId().equals(featureTypeId)) {
3240
                return type;
3241
            }
3242
        }
3243
        return null;
3244
    }
3245

    
3246
    @Override
3247
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3248
        return ((DefaultFeature) feature).getData();
3249
    }
3250

    
3251
    @Override
3252
    public DataStore getStore() {
3253
        return this;
3254
    }
3255

    
3256
    @Override
3257
    public FeatureStore getFeatureStore() {
3258
        return this;
3259
    }
3260

    
3261
    @Override
3262
    public void createCache(String name, DynObject parameters)
3263
        throws DataException {
3264
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3265
        if (cache == null) {
3266
            throw new CreateException("FeaureCacheProvider", null);
3267
        }
3268
        cache.apply(this, provider);
3269
        provider = cache;
3270

    
3271
        featureCount = null;
3272
    }
3273

    
3274
    @Override
3275
    public FeatureCache getCache() {
3276
        return cache;
3277
    }
3278

    
3279
    @Override
3280
    public void clear() {
3281
        if (metadata != null) {
3282
            metadata.clear();
3283
        }
3284
    }
3285

    
3286
    @Override
3287
    public String getName() {
3288
        if( this.provider != null ) {
3289
            return this.provider.getName();
3290
        }
3291
        if( this.parameters instanceof HasAFile ) {
3292
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
3293
        }
3294
        return "unknow";
3295
    }
3296

    
3297
    @Override
3298
    public String getFullName() {
3299
        try {
3300
            if( this.provider!=null ) {
3301
                return this.provider.getFullName();
3302
            }
3303
            if( this.parameters instanceof HasAFile ) {
3304
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
3305
            }
3306
            return null;
3307
        } catch(Throwable th) {
3308
            return null;
3309
        }
3310
    }
3311

    
3312
    @Override
3313
    public String getProviderName() {
3314
        if( this.provider!=null ) {
3315
            return this.provider.getProviderName();
3316
        }
3317
        if( this.parameters != null ) {
3318
            return this.parameters.getDataStoreName();
3319
        }
3320
        return null;
3321

    
3322
    }
3323

    
3324
    @Override
3325
    public boolean isKnownEnvelope() {
3326
        return this.provider.isKnownEnvelope();
3327
    }
3328

    
3329
    @Override
3330
    public boolean hasRetrievedFeaturesLimit() {
3331
        return this.provider.hasRetrievedFeaturesLimit();
3332
    }
3333

    
3334
    @Override
3335
    public int getRetrievedFeaturesLimit() {
3336
        return this.provider.getRetrievedFeaturesLimit();
3337
    }
3338

    
3339
    @Override
3340
    public Interval getInterval() {
3341
        if( this.timeSupport!=null ) {
3342
            return this.timeSupport.getInterval();
3343
        }
3344
        try {
3345
            FeatureType type = this.getDefaultFeatureType();
3346
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3347
            if( attr!=null ) {
3348
                Interval interval = attr.getInterval();
3349
                if( interval!=null ) {
3350
                    return interval;
3351
                }
3352
            }
3353
        } catch (DataException ex) {
3354
        }
3355
        return this.provider.getInterval();
3356
    }
3357

    
3358
    @Override
3359
    public Collection getTimes() {
3360
        if( this.timeSupport!=null ) {
3361
            return this.timeSupport.getTimes();
3362
        }
3363
        return this.provider.getTimes();
3364
    }
3365

    
3366
    @Override
3367
    public Collection getTimes(Interval interval) {
3368
        if( this.timeSupport!=null ) {
3369
            return this.timeSupport.getTimes(interval);
3370
        }
3371
        return this.provider.getTimes(interval);
3372
    }
3373

    
3374
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3375
        if( this.isEditing() ) {
3376
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
3377
        }
3378
        if( !this.transforms.isEmpty() ) {
3379
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
3380
        }
3381
        FeatureType ft = this.defaultFeatureType;
3382
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3383
        if( attr == null ) {
3384
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
3385
        }
3386
        EditableFeatureType eft = ft.getEditable();
3387
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3388
        if( attr != null ) {
3389
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
3390
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
3391
            }
3392
            eft.remove(attr.getName());
3393
        }
3394
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3395
            timeSupport.getAttributeName(), 
3396
            timeSupport.getDataType()
3397
        );
3398
        attrTime.setIsTime(true);
3399
        attrTime.setFeatureAttributeEmulator(timeSupport);
3400
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3401
        this.defaultFeatureType = eft.getNotEditableCopy();
3402
        
3403
        this.timeSupport = timeSupport;
3404
    }
3405

    
3406
    @Override
3407
    @SuppressWarnings("CloneDoesntCallSuperClone")
3408
    public Object clone() throws CloneNotSupportedException {
3409

    
3410
        DataStoreParameters dsp = getParameters();
3411

    
3412
        DefaultFeatureStore cloned_store = null;
3413

    
3414
        try {
3415
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3416
                openStore(this.getProviderName(), dsp);
3417
            if (transforms != null) {
3418
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3419
                cloned_store.transforms.setStoreForClone(cloned_store);
3420
            }
3421
        } catch (Exception e) {
3422
            throw new CloneException(e);
3423
        }
3424
        return cloned_store;
3425

    
3426
    }
3427

    
3428
    @Override
3429
    public Feature getFeature(DynObject dynobject) {
3430
        if (dynobject instanceof DynObjectFeatureFacade){
3431
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
3432
            return f;
3433
        }
3434
        return null;
3435
    }
3436

    
3437
    @Override
3438
    public Iterator iterator() {
3439
        FeatureSet fset = null;
3440
        try {
3441
            fset  = this.getFeatureSet();
3442
            return fset.fastIterator();
3443
        } catch (DataException ex) {
3444
            throw new RuntimeException(ex);
3445
        } finally {
3446
            DisposeUtils.disposeQuietly(fset);
3447
        }
3448
    }
3449

    
3450
    @Override
3451
    public long size64() {
3452
        FeatureSet fset = null;
3453
        try {
3454
            fset  = this.getFeatureSet();
3455
            return fset.getSize();
3456
        } catch (DataException ex) {
3457
            throw new RuntimeException(ex);
3458
        } finally {
3459
            DisposeUtils.disposeQuietly(fset);
3460
        }
3461
    }
3462
   
3463
    @Override
3464
    public ExpressionBuilder createExpressionBuilder() {
3465
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3466
        return builder;
3467
    }
3468

    
3469
    @Override
3470
    public ExpressionBuilder createExpression() {
3471
        return createExpressionBuilder();
3472
    }
3473

    
3474
    public FeatureSet features() throws DataException {
3475
        // This is to avoid jython to create a property with this name
3476
        // to access method getFeatures.
3477
        return this.getFeatureSet();
3478
    }
3479

    
3480
    @Override
3481
    public DataStoreProviderFactory getProviderFactory() {
3482
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3483
        return factory;
3484
    }
3485

    
3486
    @Override
3487
    public void useCache(String providerName, DynObject parameters) throws DataException {
3488
        throw new UnsupportedOperationException();
3489
    }
3490

    
3491
    @Override
3492
    public boolean isBroken() {
3493
        return this.state.isBroken();
3494
    }
3495

    
3496
    @Override
3497
    public Throwable getBreakingsCause() {
3498
            return this.state.getBreakingsCause();
3499
    }
3500

    
3501
    @Override
3502
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3503
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3504
      if( !factory.supportNumericOID() ) {
3505
          return null;
3506
      }
3507
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3508
      return wrappedIndex;
3509
  }
3510

    
3511
    @Override
3512
    public FeatureReference getFeatureReference(String code) {
3513
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3514
        return featureReference;
3515
    }
3516

    
3517
    @Override
3518
    public long getPendingChangesCount() {
3519
        if( this.featureManager==null ) {
3520
            return 0;
3521
        }
3522
        return this.featureManager.getPendingChangesCount();
3523
    }
3524

    
3525
    @Override
3526
    public ResourcesStorage getResourcesStorage() {
3527
        ResourcesStorage resourcesStorage;
3528
        try {
3529
            resourcesStorage = this.provider.getResourcesStorage();
3530
            if( resourcesStorage!=null ) {
3531
                return resourcesStorage;
3532
            }
3533
        } catch(Throwable th) {
3534
            
3535
        }
3536
        try {
3537
            DataServerExplorer explorer = this.getExplorer();
3538
            if( explorer==null ) {
3539
                return null;
3540
            }
3541
            resourcesStorage = explorer.getResourcesStorage(this);
3542
            explorer.dispose();
3543
            return resourcesStorage;
3544
        } catch (Exception ex) {
3545
            LOGGER.trace("Can't create resources storage",ex);
3546
            return null;
3547
        }
3548
    }
3549

    
3550
    @Override
3551
    public StoresRepository getStoresRepository() {
3552
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3553
        StoresRepository localRepository = this.provider.getStoresRepository();
3554
        if( localRepository==null ) {
3555
            return mainRepository;
3556
        }
3557
        StoresRepository repository = new BaseStoresRepository(this.getName());
3558
        repository.addRepository(localRepository);
3559
        repository.addRepository(mainRepository);
3560
        return repository;
3561
    }
3562

    
3563
    @Override
3564
    public Feature getSampleFeature() {
3565
            Feature sampleFeature;
3566
            try {
3567
                FeatureSelection theSelection = this.getFeatureSelection();
3568
                if( theSelection!=null && !theSelection.isEmpty() ) {
3569
                    sampleFeature = theSelection.first();
3570
                } else {
3571
                    sampleFeature = this.first();
3572
                }
3573
                if( sampleFeature==null ) {
3574
                    sampleFeature = this.createNewFeature();
3575
                }
3576
            } catch (DataException ex) {
3577
                return null;
3578
            }
3579
            return sampleFeature;
3580
    }
3581

    
3582
    @Override
3583
    public boolean supportReferences() {
3584
        try {
3585
            return this.getDefaultFeatureType().supportReferences();
3586
        } catch (Exception ex) {
3587
            return false;
3588
        }
3589
    }
3590

    
3591
    @Override
3592
    public boolean isTemporary() {
3593
        if( this.provider==null ) {
3594
            return true;
3595
        }
3596
        return this.provider.isTemporary();
3597
    }
3598
    
3599
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3600
        // FIXME this don't work for Store.fType.size() > 1
3601
        FeatureTypeManager manager = this.featureTypeManager;
3602
         if (manager==null) {
3603
             return null;
3604
         }
3605
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3606
         if (originalFeatureType==null) {
3607
             return null;
3608
         }
3609
         return originalFeatureType.getCopy();
3610
    }
3611

    
3612
    @Override
3613
    public Object getProperty(String name) {
3614
        if( this.propertiesSupportHelper==null ) {
3615
            return null;
3616
        }
3617
        return this.propertiesSupportHelper.getProperty(name);
3618
    }
3619

    
3620
    @Override
3621
    public void setProperty(String name, Object value) {
3622
        if( this.propertiesSupportHelper==null ) {
3623
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3624
        }
3625
        this.propertiesSupportHelper.setProperty(name,value);
3626
    }
3627

    
3628
    @Override
3629
    public Map<String, Object> getProperties() {
3630
        if( this.propertiesSupportHelper==null ) {
3631
            return Collections.EMPTY_MAP;
3632
        }
3633
        return this.propertiesSupportHelper.getProperties();
3634
    }
3635
    
3636
    @Override
3637
    public Feature getOriginalFeature(FeatureReference id){
3638
        if(this.featureManager == null){
3639
            return null;
3640
        }
3641
        return featureManager.getOriginal(id);
3642
    }
3643

    
3644
    @Override
3645
    public Feature getOriginalFeature(Feature feature){
3646
        if(feature == null){
3647
            return null;
3648
        }
3649
        return getOriginalFeature(feature.getReference());
3650
    }
3651

    
3652
    @Override
3653
    public boolean isFeatureModified(FeatureReference id){
3654
        if(this.featureManager == null){
3655
            return false;
3656
        }
3657
        return featureManager.isFeatureModified(id);
3658
    }
3659

    
3660
    @Override
3661
    public boolean isFeatureModified(Feature feature){
3662
        if(feature == null){
3663
            return false;
3664
        }
3665
        return isFeatureModified(feature.getReference());
3666
    }
3667

    
3668

    
3669
}