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

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

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

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

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

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

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

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

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

    
214
    private DefaultDataManager dataManager = null;
215

    
216
    private FeatureStoreProvider provider = null;
217

    
218
    private DefaultFeatureIndexes indexes;
219

    
220
    private DefaultFeatureStoreTransforms transforms;
221

    
222
    /*friend*/ DelegatedDynObject metadata;
223

    
224
    private Set metadataChildren;
225

    
226
    private Long featureCount = null;
227

    
228
    private long temporalOid = 0;
229

    
230
    private FeatureCacheProvider cache;
231

    
232
    private final StateInformation state;
233

    
234
    private FeatureStoreTimeSupport timeSupport;
235
    
236
    private PropertiesSupportHelper propertiesSupportHelper;
237
    private DataTransaction transaction;
238

    
239
    private class StateInformation extends HashMap<Object, Object> {
240

    
241
        private static final long serialVersionUID = 4109026189635185666L;
242

    
243
        private boolean broken;
244
        private Throwable breakingsCause;
245

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

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

    
258
        public boolean isBroken() {
259
            return this.broken;
260
        }
261

    
262
        public void broken() {
263
            this.broken = true;
264
        }
265

    
266
        public Throwable getBreakingsCause() {
267
            return this.breakingsCause;
268
        }
269

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

    
278

    
279

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

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

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

    
302
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
303

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

    
309
        this.dataManager = (DefaultDataManager) dataManager;
310

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

    
319
    }
320

    
321
    @Override
322
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
323
        this.provider = (FeatureStoreProvider) provider;
324
        this.delegate((DynObject) provider);
325
        this.metadataChildren = new HashSet();
326
        this.metadataChildren.add(provider);
327
        loadDALFile();
328

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

    
358
    @Override
359
    public int getMode() {
360
        return this.mode;
361
    }
362

    
363
    @Override
364
    public DataManager getManager() {
365
        return this.dataManager;
366
    }
367

    
368
    @Override
369
    public UnmodifiableBasicMap<String,DataStore> getChildren() {
370
        UnmodifiableBasicMap<String, DataStore> children = this.provider.getChildren();
371
        if( children == null ) {
372
            return UnmodifiableBasicMap.EMPTY_UNMODIFIABLEBASICMAP;
373
        }
374
        return children;
375
    }
376

    
377
    @Override
378
    public FeatureStoreProvider getProvider() {
379
        return this.provider;
380
    }
381

    
382
    public FeatureManager getFeatureManager() {
383
        return this.featureManager;
384
    }
385

    
386
    @Override
387
    public void setFeatureTypes(List types, FeatureType defaultType) {
388
        this.featureTypes = types;
389
        this.defaultFeatureType = defaultType;
390
    }
391

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

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

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

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

    
470
        if (this.featureTypeManager != null) {
471
            this.featureTypeManager.dispose();
472
            this.featureTypeManager = null;
473
        }
474

    
475
        this.featureManager = null;
476
        this.spatialManager = null;
477

    
478
        this.parameters = null;
479
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
480
        if (delegateObservable != null) {
481
            this.delegateObservable.deleteObservers();
482
            this.delegateObservable = null;
483
        }
484
    }
485

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

    
495
    @Override
496
    public boolean canWriteGeometry(int geometryType) throws DataException {
497
        return this.provider.canWriteGeometry(geometryType, 0);
498
    }
499

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

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

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

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

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

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

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

    
627
        }
628

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

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

    
636
    }
637

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

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

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

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

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

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

    
750
                    }
751

    
752
            }
753
        } catch(Throwable th) {
754
            state.setBreakingsCause(th);
755
        }
756

    
757

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

    
762
            if (defaultFeatureType == null ||
763
                    defaultFeatureType.getId() == null ||
764
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
765

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

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

    
790
    public DataStoreProviderServices getStoreProviderServices() {
791
        return this;
792
    }
793

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

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

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

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

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

    
820
            definition.addDynFieldString("defaultFeatureTypeId")
821
                .setMandatory(true).setPersistent(true);
822
        }
823
    }
824

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

    
835
    //
836
    // ====================================================================
837
    // Gestion de la seleccion
838
    //
839

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

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

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

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

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

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

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

    
914
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
915
    }
916

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

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

    
946
    //
947
    // ====================================================================
948
    // Gestion de notificaciones
949
    //
950

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

    
963
    @Override
964
    public FeatureStoreNotification notifyChange(String notification) {
965
      return notifyChange(new DefaultFeatureStoreNotification(this, notification));
966
    }
967
    
968
    public FeatureStoreNotification notifyChange(String notification,
969
      Iterator<FeatureReference> deleteds, 
970
      Iterator<Feature> inserteds, 
971
      Iterator<Feature> updateds, 
972
      Iterator<FeatureTypeChanged> featureTypesChanged, 
973
      boolean isSelectionCompromised) {
974
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
975
            deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised));
976
    }
977

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

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

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

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

    
1006
    @Override
1007
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
1008
        return notifyChange(new DefaultFeatureStoreNotification(this,
1009
            DataStoreNotification.RESOURCE_CHANGED));
1010
    }
1011

    
1012
    //
1013
    // ====================================================================
1014
    // Gestion de bloqueos
1015
    //
1016

    
1017
    @Override
1018
    public boolean isLocksSupported() {
1019
        return this.provider.isLocksSupported();
1020
    }
1021

    
1022
    @Override
1023
    public FeatureLocks getLocks() throws DataException {
1024
        if (!this.provider.isLocksSupported()) {
1025
            LOGGER.warn("Locks not supported");
1026
            return null;
1027
        }
1028
        if (locks == null) {
1029
            this.locks = this.provider.createFeatureLocks();
1030
        }
1031
        return locks;
1032
    }
1033

    
1034
    //
1035
    // ====================================================================
1036
    // Interface Observable
1037
    //
1038

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

    
1043
    }
1044

    
1045
    @Override
1046
    public void enableNotifications() {
1047
        this.delegateObservable.enableNotifications();
1048
    }
1049

    
1050
    @Override
1051
    public void beginComplexNotification() {
1052
        this.delegateObservable.beginComplexNotification();
1053

    
1054
    }
1055

    
1056
    @Override
1057
    public void endComplexNotification() {
1058
        this.delegateObservable.endComplexNotification();
1059

    
1060
    }
1061

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

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

    
1076
    @Override
1077
    public void deleteObservers() {
1078
        this.delegateObservable.deleteObservers();
1079

    
1080
    }
1081

    
1082
    //
1083
    // ====================================================================
1084
    // Interface Observer
1085
    //
1086
    // Usado para observar:
1087
    // - su seleccion
1088
    // - sus bloqueos
1089
    // - sus recursos
1090
    //
1091

    
1092
    @Override
1093
    public void update(Observable observable, Object notification) {
1094
        if (observable instanceof FeatureSet) {
1095
            if (observable == this.selection) {
1096
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1097
            } else if (observable == this.locks) {
1098
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1099
            }
1100

    
1101
        } else if (observable instanceof FeatureStoreProvider) {
1102
            if (observable == this.provider) {
1103

    
1104
            }
1105
        } else if (observable instanceof FeatureReferenceSelection) {
1106
            if(notification instanceof String){
1107
                    this.notifyChange((String)notification);
1108
            }
1109
        }
1110
    }
1111

    
1112
    //
1113
    // ====================================================================
1114
    // Edicion
1115
    //
1116

    
1117
    private void newVersionOfUpdate() {
1118
        this.versionOfUpdate++;
1119
    }
1120

    
1121
    private long currentVersionOfUpdate() {
1122
        return this.versionOfUpdate;
1123
    }
1124

    
1125
    private void checkInEditingMode() throws NeedEditingModeException {
1126
        if (mode != MODE_FULLEDIT) {
1127
            throw new NeedEditingModeException(this.getName());
1128
        }
1129
    }
1130

    
1131
    private void checkNotInAppendMode() throws IllegalStateException {
1132
        if (mode == MODE_APPEND) {
1133
                        throw new IllegalStateException("Error: store "
1134
                                        + this.getFullName() + " is in append mode");
1135
        }
1136
    }
1137

    
1138
    private void checkIsOwnFeature(Feature feature)
1139
        throws IllegalFeatureException {
1140
        if (((DefaultFeature) feature).getStore() != this) {
1141
            throw new IllegalFeatureException(this.getName());
1142
        }
1143
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1144
        // fixFeatureType((DefaultFeatureType) feature.getType());
1145
    }
1146

    
1147
    private void exitEditingMode() {
1148
        if (commands != null) {
1149
            commands.clear();
1150
            commands = null;
1151
        }
1152

    
1153
        if (featureTypeManager != null) {
1154
            featureTypeManager.dispose();
1155
            featureTypeManager = null;
1156

    
1157
        }
1158

    
1159
        // TODO implementar un dispose para estos dos
1160
        featureManager = null;
1161
        spatialManager = null;
1162

    
1163
        featureCount = null;
1164

    
1165
        mode = MODE_QUERY;
1166
        hasStrongChanges = true; // Lo deja a true por si las moscas
1167
        hasInserts = true;
1168
    }
1169

    
1170
    @Override
1171
    synchronized public void edit() throws DataException {
1172
        edit(MODE_FULLEDIT);
1173
    }
1174

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

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

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

    
1245
    private void invalidateIndexes() {
1246
        setIndexesValidStatus(false);
1247
    }
1248

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

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

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

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

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

    
1310
    @Override
1311
    public boolean isAppending() {
1312
        return mode == MODE_APPEND;
1313
    }
1314

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

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

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

    
1453
            //Update the featureManager and the spatialManager
1454
            featureManager.delete(feature);
1455
            spatialManager.deleteFeature(feature);
1456

    
1457
            newVersionOfUpdate();
1458
            hasStrongChanges = true;
1459
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1460
        } catch (Exception e) {
1461
            throw new StoreDeleteFeatureException(e, this.getName());
1462
        }
1463
    }
1464

    
1465
    @Override
1466
    public synchronized void insert(FeatureSet set) throws DataException {
1467
        switch (mode) {
1468
        case MODE_QUERY:
1469
            throw new NeedEditingModeException(this.getName());
1470

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

    
1488
    @Override
1489
    public synchronized void insert(EditableFeature feature)
1490
        throws DataException {
1491
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1492
        try {
1493
            switch (mode) {
1494
            case MODE_QUERY:
1495
                throw new NeedEditingModeException(this.getName());
1496

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

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

    
1539
    synchronized public void doInsert(EditableFeature feature)
1540
        throws DataException {
1541
        checkIsOwnFeature(feature);
1542

    
1543
        waitForIndexes();
1544

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

    
1559

    
1560
        featureManager.add(newFeature);
1561
        spatialManager.insertFeature(newFeature);
1562

    
1563
        hasStrongChanges = true;
1564
        hasInserts = true;
1565
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1566
    }
1567

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

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

    
1655
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1656
        throws DataException {
1657
        try {
1658
            checkInEditingMode();
1659
            checkIsOwnFeature(feature);
1660
            if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled() ) {
1661
              return;
1662
            }
1663
            newVersionOfUpdate();
1664
            if ((lastChangedFeature == null)
1665
                || (lastChangedFeature.getSource() != feature.getSource())) {
1666
                lastChangedFeature = feature;
1667
                feature.validate(Feature.UPDATE);
1668
                lastChangedFeature = null;
1669
            }
1670

    
1671
            //Update the featureManager and the spatialManager
1672
            Feature newf = feature.getNotEditableCopy();
1673
            featureManager.update(newf, oldFeature);
1674
            spatialManager.updateFeature(newf, oldFeature);
1675

    
1676
            hasStrongChanges = true;
1677
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1678
        } catch (Exception e) {
1679
            throw new StoreUpdateFeatureException(e, this.getName());
1680
        }
1681
    }
1682

    
1683
    @Override
1684
    synchronized public void redo() throws RedoException {
1685
        Command redo = commands.getNextRedoCommand();
1686
        try {
1687
            checkInEditingMode();
1688
        } catch (NeedEditingModeException ex) {
1689
            throw new RedoException(redo, ex);
1690
        }
1691
        if( notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled() ) {
1692
          return;
1693
        }
1694
        newVersionOfUpdate();
1695
        commands.redo();
1696
        hasStrongChanges = true;
1697
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1698
    }
1699

    
1700
    @Override
1701
    synchronized public void undo() throws UndoException {
1702
        Command undo = commands.getNextUndoCommand();
1703
        try {
1704
            checkInEditingMode();
1705
        } catch (NeedEditingModeException ex) {
1706
            throw new UndoException(undo, ex);
1707
        }
1708
        if( notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled() ) {
1709
          return;
1710
        }
1711
        newVersionOfUpdate();
1712
        commands.undo();
1713
        hasStrongChanges = true;
1714
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1715
    }
1716

    
1717
    @Override
1718
    public List getRedoInfos() {
1719
        if (isEditing() && (commands != null)) {
1720
            return commands.getRedoInfos();
1721
        } else {
1722
            return null;
1723
        }
1724
    }
1725

    
1726
    @Override
1727
    public List getUndoInfos() {
1728
        if (isEditing() && (commands != null)) {
1729
            return commands.getUndoInfos();
1730
        } else {
1731
            return null;
1732
        }
1733
    }
1734

    
1735
    public synchronized FeatureCommandsStack getCommandsStack()
1736
        throws DataException {
1737
        checkInEditingMode();
1738
        return commands;
1739
    }
1740

    
1741
    @Override
1742
    public boolean cancelEditingQuietly() {
1743
        try {
1744
            this.cancelEditing();
1745
            return true;
1746
        } catch(Exception ex) {
1747
            LOGGER.debug("Can't cancel editing", ex);
1748
            return false;
1749
        }
1750
    }
1751
    
1752
    @Override
1753
    synchronized public void cancelEditing() throws DataException {
1754
        if( spatialManager!=null ) {
1755
            spatialManager.cancelModifies();
1756
        }
1757
        try {
1758
            switch (mode) {
1759
            case MODE_QUERY:
1760
                throw new NeedEditingModeException(this.getName());
1761

    
1762
            case MODE_APPEND:
1763
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1764
                  return;
1765
                }
1766
                provider.abortAppend();
1767
                exitEditingMode();
1768
                ((FeatureSelection) this.getSelection()).deselectAll();
1769
                updateIndexes();
1770
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1771
                break;
1772

    
1773
            case MODE_FULLEDIT:
1774
                boolean clearSelection = this.hasStrongChanges;
1775
                if (this.selection instanceof FeatureReferenceSelection) {
1776
                    clearSelection = this.hasInserts;
1777
                }
1778
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1779
                  return;
1780
                }
1781
                exitEditingMode();
1782
                if (clearSelection) {
1783
                    ((FeatureSelection) this.getSelection()).deselectAll();
1784
                }
1785
                updateIndexes();
1786
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);  
1787
                break;
1788

    
1789
            case MODE_PASS_THROUGH:
1790
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1791
                  return;
1792
                }
1793
                exitEditingMode();
1794
                ((FeatureSelection) this.getSelection()).deselectAll();
1795
                updateIndexes();
1796
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);  
1797
                break;
1798
            }
1799
        } catch (Exception e) {
1800
            throw new StoreCancelEditingException(e, this.getName());
1801
        }
1802
    }
1803

    
1804
    @Override
1805
    public boolean finishEditingQuietly() {
1806
        try {
1807
            this.finishEditing();
1808
            return true;
1809
        } catch(Exception ex) {
1810
            LOGGER.debug("Can't finish editing", ex);
1811
            return false;
1812
        }
1813
    }
1814
    
1815
    @Override
1816
    synchronized public void finishEditing() throws DataException {
1817
        LOGGER.debug("finish editing of mode: {}", mode);
1818
        try {
1819

    
1820
            /*
1821
             * Selection needs to be cleared when editing stops
1822
             * to prevent conflicts with selection remaining from
1823
             * editing mode.
1824
             */
1825
//            ((FeatureSelection) this.getSelection()).deselectAll();
1826
            Map<String,List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1827
            switch (mode) {
1828
            case MODE_QUERY:
1829
                throw new NeedEditingModeException(this.getName());
1830

    
1831
            case MODE_APPEND:
1832
                if( selection!=null ) {
1833
                    selection = null;
1834
                }
1835
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled() ) {
1836
                  return;
1837
                }
1838
                saveDALFile();
1839
                provider.endAppend();
1840
                exitEditingMode();
1841
                this.updateComputedFields(computedFields);
1842
                loadDALFile();
1843
                updateIndexes();
1844
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1845
                break;
1846

    
1847
            case MODE_FULLEDIT:
1848
                if( featureManager.hasChanges() || featureTypeManager.hasChanges() )  {
1849
                    if (hasStrongChanges && !this.allowWrite()) {
1850
                        throw new WriteNotAllowedException(getName());
1851
                    }
1852
                    if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, 
1853
                            featureManager.getDeleted(),
1854
                            featureManager.getInsertedFeatures(),
1855
                            featureManager.getUpdatedFeatures(),
1856
                            featureTypeManager.getFeatureTypesChanged().iterator(),
1857
                            featureManager.isSelectionCompromised()).isCanceled() ) {
1858
                      return;
1859
                    }
1860
                    saveDALFile();
1861
                    if(featureManager.isSelectionCompromised() && selection!=null ) {
1862
                        selection = null;
1863
                    }
1864
                    if (hasStrongChanges) {
1865
                        validateFeatures(Feature.FINISH_EDITING);
1866

    
1867
                        /*
1868
                         * This will throw a PerformEditingExceptionif the provider
1869
                         * does not accept the changes (for example, an invalid field name)
1870
                         */
1871
                        provider.performChanges(featureManager.getDeleted(),
1872
                            featureManager.getInserted(),
1873
                            featureManager.getUpdated(),
1874
                            removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1875

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

    
1930
        List<FeatureType> theTypes = new ArrayList<>();
1931
        theTypes.addAll(this.getFeatureTypes());
1932
        theTypes.add(this.getDefaultFeatureType());
1933
        for( int n=0; n<theTypes.size(); n++ ) {
1934
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1935
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1936
            if(x!=null && !x.isEmpty()) {
1937
                for (FeatureAttributeDescriptor attrdesc : x) {
1938
                    if (type.get(attrdesc.getName())==null) {
1939
                        type.add(attrdesc);
1940
                    }
1941
                }
1942
            }
1943
        }
1944
        
1945
    }
1946
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
1947
        // FIXME: Falta por implementar
1948
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
1949
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
1950
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
1951
//                if (attributeDescriptor.isComputed()) {
1952
//                    target.remove(attributeDescriptor.getName());
1953
//                }
1954
//            }
1955
//        }
1956
        return ftypes;
1957
    }
1958
    
1959

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

    
2024
        case MODE_APPEND:
2025
          this.provider.endAppend();
2026
          exitEditingMode();
2027
          invalidateIndexes();
2028
          this.provider.beginAppend();
2029
          hasInserts = false;
2030
          break;
2031

    
2032
        case MODE_FULLEDIT:
2033
          if (hasStrongChanges && !this.allowWrite()) {
2034
            throw new WriteNotAllowedException(getName());
2035
          }
2036
          if (hasStrongChanges) {
2037
            validateFeatures(Feature.FINISH_EDITING);
2038
            provider.performChanges(featureManager.getDeleted(),
2039
              featureManager.getInserted(),
2040
              featureManager.getUpdated(),
2041
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2042
          }
2043
          invalidateIndexes();
2044
          featureManager = new FeatureManager(this);
2045
          featureTypeManager = new FeatureTypeManager(this);
2046
          spatialManager = new SpatialManager(this, provider.getEnvelope());
2047

    
2048
          commands =
2049
            new DefaultFeatureCommandsStack(this, featureManager,
2050
              spatialManager, featureTypeManager);
2051
          featureCount = null;
2052
          hasStrongChanges = false;
2053
          hasInserts = false;
2054
          break;
2055
        }
2056
      } catch (Exception e) {
2057
        throw new FinishEditingException(e);
2058
      }
2059
    }
2060

    
2061
    @Override
2062
    synchronized public boolean canCommitChanges() throws DataException {
2063
        if ( !this.allowWrite()) {
2064
                return false;
2065
        }
2066
            switch (mode) {
2067
            default:
2068
        case MODE_QUERY:
2069
                return false;
2070

    
2071
        case MODE_APPEND:
2072
                return true;
2073

    
2074
        case MODE_FULLEDIT:
2075
            List types = this.getFeatureTypes();
2076
            for( int i=0; i<types.size(); i++ ) {
2077
                    Object type = types.get(i);
2078
                    if( type instanceof DefaultEditableFeatureType ) {
2079
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
2080
                                    return false;
2081
                            }
2082
                    }
2083
            }
2084
            return true;
2085
            }
2086
    }
2087

    
2088
    @Override
2089
    public void beginEditingGroup(String description)
2090
        throws NeedEditingModeException {
2091
        checkInEditingMode();
2092
        commands.startComplex(description);
2093
    }
2094

    
2095
    @Override
2096
    public void endEditingGroup() throws NeedEditingModeException {
2097
        checkInEditingMode();
2098
        commands.endComplex();
2099
    }
2100

    
2101
    @Override
2102
    public boolean isAppendModeSupported() {
2103
        return this.provider.supportsAppendMode();
2104
    }
2105

    
2106
    @Override
2107
    public void export(DataServerExplorer explorer, String provider,
2108
        NewFeatureStoreParameters params, String name) throws DataException {
2109

    
2110
        if (this.getFeatureTypes().size() != 1) {
2111
            throw new NotYetImplemented(
2112
                "export whith more than one type not yet implemented");
2113
        }
2114
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2115
        FeatureStore target = null;
2116
        FeatureSet features = null;
2117
        DisposableIterator iterator = null;
2118
        try {
2119
            FeatureType type = this.getDefaultFeatureType();
2120
            if ((params.getDefaultFeatureType() == null)
2121
                || (params.getDefaultFeatureType().size() == 0)) {
2122
                params.setDefaultFeatureType(type.getEditable());
2123

    
2124
            }
2125
            explorer.add(provider, params, true);
2126
            DataManager manager = DALLocator.getDataManager();
2127
            
2128
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2129
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2130

    
2131
            target = (FeatureStore) manager.openStore(provider, openParams);
2132
            FeatureType targetType = target.getDefaultFeatureType();
2133

    
2134
            target.edit(MODE_APPEND);
2135
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
2136
            if (featureSelection.getSize() > 0) {
2137
                features = this.getFeatureSelection();
2138
            } else {
2139
                if ((pkattrs != null) && (pkattrs.length > 0)) {
2140
                    FeatureQuery query = createFeatureQuery();
2141
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
2142
                        query.getOrder().add(pkattr.getName(), true);
2143
                    }
2144
                    features = this.getFeatureSet(query);
2145
                } else {
2146
                    features = this.getFeatureSet();
2147
                }
2148
            }
2149
            iterator = features.fastIterator();
2150
            while (iterator.hasNext()) {
2151
                DefaultFeature feature = (DefaultFeature) iterator.next();
2152
                target.insert(target.createNewFeature(targetType, feature));
2153
            }
2154
            target.finishEditing();
2155
            target.dispose();
2156
        } catch (Exception e) {
2157
            throw new DataExportException(e, params.toString());
2158
        } finally {
2159
            dispose(iterator);
2160
            dispose(features);
2161
            dispose(target);
2162
        }
2163
    }
2164

    
2165
    @Override
2166
    public void copyTo(final FeatureStore target) {
2167
        boolean finishEditingAtEnd = false;
2168
        try {
2169
            if( !target.isEditing() && !target.isAppending() ) {
2170
                finishEditingAtEnd = true;
2171
                target.edit(MODE_APPEND);
2172
            }
2173
            this.accept((Object obj) -> {
2174
                Feature f_src = (Feature) obj;
2175
                EditableFeature f_dst = target.createNewFeature(f_src);
2176
                target.insert(f_dst);
2177
            });
2178
            if( finishEditingAtEnd ) {
2179
                target.finishEditing();
2180
            }
2181
            
2182
        } catch(Exception ex) {
2183
            try {
2184
                if( finishEditingAtEnd ) {
2185
                    target.cancelEditing();
2186
                }
2187
            } catch (Exception ex1) {
2188
            }
2189
            throw new RuntimeException("Can't copy store.",ex);
2190
        }
2191
            
2192
    }
2193
    
2194
    //
2195
    // ====================================================================
2196
    // Obtencion de datos
2197
    // getDataCollection, getFeatureCollection
2198
    //
2199

    
2200
    @Override
2201
    public DataSet getDataSet() throws DataException {
2202
        checkNotInAppendMode();
2203
        FeatureQuery query =
2204
            new DefaultFeatureQuery(this.getDefaultFeatureType());
2205
        return new DefaultFeatureSet(this, query);
2206
    }
2207

    
2208
    @Override
2209
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2210
        checkNotInAppendMode();
2211
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2212
    }
2213

    
2214
    @Override
2215
    public void getDataSet(Observer observer) throws DataException {
2216
        checkNotInAppendMode();
2217
        this.getFeatureSet(null, observer);
2218
    }
2219

    
2220
    @Override
2221
    public void getDataSet(DataQuery dataQuery, Observer observer)
2222
        throws DataException {
2223
        checkNotInAppendMode();
2224
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2225
    }
2226

    
2227
    @Override
2228
    public FeatureSet getFeatureSet() throws DataException {
2229
        return this.getFeatureSet((FeatureQuery)null);
2230
    }
2231

    
2232
    @Override
2233
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2234
        throws DataException {
2235
        checkNotInAppendMode();
2236
        if( featureQuery==null ) {
2237
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2238
        }
2239
        return new DefaultFeatureSet(this, featureQuery);
2240
    }
2241

    
2242
    @Override
2243
    public FeatureSet getFeatureSet(String filter) throws DataException {
2244
        return this.getFeatureSet(filter, null, true);
2245
    }
2246

    
2247
    @Override
2248
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2249
        return this.getFeatureSet(filter, sortBy, true);
2250
    }
2251

    
2252
    @Override
2253
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2254
        return this.getFeatureSet(filter, null, true);
2255
    }
2256
    
2257
    @Override
2258
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2259
        return this.getFeatureSet(filter, sortBy, true);
2260
    }
2261

    
2262
    @Override
2263
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2264
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2265
        return this.getFeatureSet(query);
2266
    }
2267
    
2268
    @Override
2269
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2270
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2271
        return this.getFeatureSet(query);
2272
    }
2273
    
2274
    @Override
2275
    public List<Feature> getFeatures(String filter)  {
2276
        return this.getFeatures(filter, null, true);
2277
    }
2278

    
2279
    @Override
2280
    public List<Feature> getFeatures(String filter, String sortBy)  {
2281
        return this.getFeatures(filter, sortBy, true);
2282
    }
2283

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

    
2295
    @Override
2296
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
2297
        return this.getFeatures(filter, sortBy, true);
2298
    }
2299

    
2300
    @Override
2301
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
2302
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2303
        return this.getFeatures(query, 0);
2304
    }
2305
    
2306
    @Override
2307
    public List<Feature> getFeatures(FeatureQuery query)  {
2308
        return this.getFeatures(query, 0);
2309
    }
2310
    
2311
    @Override
2312
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
2313
        try {
2314
            if( pageSize<=0 ) {
2315
                pageSize = 100;
2316
            }
2317
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2318
            return pager.asList();
2319
        } catch (BaseException ex) {
2320
            throw new RuntimeException("Can't create the list of features.", ex);
2321
        }
2322
    }
2323

    
2324
    @Override
2325
    public List<Feature> getFeatures() {
2326
        return this.getFeatures(null, 0);
2327
    }
2328

    
2329
    @Override
2330
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2331
        return this.getFeatures64(null, 0);
2332
    }
2333

    
2334
    @Override
2335
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2336
        return this.getFeatures64(filter, null, true);
2337
    }
2338
    
2339
    @Override
2340
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc)  {
2341
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2342
        return this.getFeatures64(query, 0);
2343
    }
2344

    
2345
    @Override
2346
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize)  {
2347
        try {
2348
            if( pageSize<=0 ) {
2349
                pageSize = 100;
2350
            }
2351
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2352
            return pager;
2353
        } catch (BaseException ex) {
2354
            throw new RuntimeException("Can't create the list of features.", ex);
2355
        }
2356
    }
2357

    
2358
    @Override
2359
    public Feature first() throws DataException {
2360
        return this.findFirst((FeatureQuery)null);
2361
    }
2362
    
2363
    @Override
2364
    public Feature findFirst(String filter) throws DataException {
2365
        return this.findFirst(filter, (String)null, true);
2366
    }
2367

    
2368
    @Override
2369
    public Feature findFirst(String filter, String sortBy) throws DataException {
2370
        return this.findFirst(filter, sortBy, true);
2371
    }
2372

    
2373
    @Override
2374
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2375
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2376
        return findFirst(query);
2377
    }
2378

    
2379
    @Override
2380
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2381
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2382
        return findFirst(query);
2383
    }
2384
    
2385
    @Override
2386
    public Feature findFirst(Expression filter) throws DataException {
2387
        return this.findFirst(filter, (String)null, true);
2388
    }
2389

    
2390
    @Override
2391
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2392
        return this.findFirst(filter, sortBy, true);
2393
    }
2394

    
2395
    @Override
2396
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2397
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2398
        return findFirst(query);
2399
    }
2400
    
2401
    @Override
2402
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2403
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2404
        return findFirst(query);
2405
    }
2406
    
2407
    @Override
2408
    public Feature findFirst(FeatureQuery query) throws DataException {
2409
        if( query == null ) {
2410
            query = this.createFeatureQuery();
2411
        } else {
2412
            query = query.getCopy();
2413
        }
2414
        query.setLimit(1);
2415
        final MutableObject<Feature> feature = new MutableObject<>();
2416
        try {
2417
            this.accept((Object obj) -> {
2418
                feature.setValue((Feature) obj);
2419
                throw new VisitCanceledException();
2420
            }, query);
2421
        } catch(VisitCanceledException ex) {
2422

    
2423
        } catch(DataException ex) {
2424
            throw ex;
2425
        } catch(Exception ex) {
2426
            throw new RuntimeException("", ex);
2427
        }
2428
        return feature.getValue();
2429
    }
2430

    
2431
    @Override
2432
    public void accept(Visitor visitor) throws BaseException {
2433
        this.accept(visitor, null);
2434
    }
2435

    
2436
    @Override
2437
    public void accept(Visitor visitor, DataQuery dataQuery)
2438
        throws BaseException {
2439
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2440
        try {
2441
            set.accept(visitor);
2442
        } finally {
2443
            set.dispose();
2444
        }
2445
    }
2446

    
2447
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2448
        throws DataException {
2449
        DefaultFeatureType fType =
2450
            (DefaultFeatureType) this.getFeatureType(featureQuery
2451
                .getFeatureTypeId());
2452
        if( featureQuery.hasAttributeNames() || 
2453
            featureQuery.hasConstantsAttributeNames() ||
2454
            fType.hasRequiredFields()    
2455
            ) {
2456
            if( featureQuery.hasGroupByColumns()) {
2457
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2458
            } else {
2459
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2460
            }
2461
        }
2462
        return fType;
2463
    }
2464

    
2465
    @Override
2466
    public void getFeatureSet(Observer observer) throws DataException {
2467
        checkNotInAppendMode();
2468
        this.getFeatureSet(null, observer);
2469
    }
2470

    
2471
    @Override
2472
    public void getFeatureSet(FeatureQuery query, Observer observer)
2473
        throws DataException {
2474
        class LoadInBackGround implements Runnable {
2475

    
2476
            private final FeatureStore store;
2477
            private final FeatureQuery query;
2478
            private final Observer observer;
2479

    
2480
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2481
                Observer observer) {
2482
                this.store = store;
2483
                this.query = query;
2484
                this.observer = observer;
2485
            }
2486

    
2487
            void notify(FeatureStoreNotification theNotification) {
2488
                observer.update(store, theNotification);
2489
            }
2490

    
2491
            @Override
2492
            public void run() {
2493
                FeatureSet set = null;
2494
                try {
2495
                    set = store.getFeatureSet(query);
2496
                    notify(new DefaultFeatureStoreNotification(store,
2497
                        FeatureStoreNotification.LOAD_FINISHED, set));
2498
                } catch (Exception e) {
2499
                    notify(new DefaultFeatureStoreNotification(store,
2500
                        FeatureStoreNotification.LOAD_FINISHED, e));
2501
                } finally {
2502
                    dispose(set);
2503
                }
2504
            }
2505
        }
2506

    
2507
        checkNotInAppendMode();
2508
        if (query == null) {
2509
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2510
        }
2511
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2512
        Thread thread = new Thread(task, "Load Feature Set in background");
2513
        thread.start();
2514
    }
2515

    
2516
    @Override
2517
    public Feature getFeatureByReference(FeatureReference reference)
2518
        throws DataException {
2519
        checkNotInAppendMode();
2520
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2521
        FeatureType featureType;
2522
        if (ref.getFeatureTypeId() == null) {
2523
            featureType = this.getDefaultFeatureType();
2524
        } else {
2525
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2526
        }
2527
        return this.getFeatureByReference(reference, featureType);
2528
    }
2529

    
2530
    @Override
2531
    public Feature getFeatureByReference(FeatureReference reference,
2532
        FeatureType featureType) throws DataException {
2533
        checkNotInAppendMode();
2534
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2535
        if (this.mode == MODE_FULLEDIT) {
2536
            Feature f = featureManager.get(reference, this, featureType);
2537
            if (f != null) {
2538
                return f;
2539
            }
2540
        }
2541

    
2542
        FeatureType sourceFeatureType = featureType;
2543
        if (!this.transforms.isEmpty()) {
2544
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2545
        }
2546
        // TODO comprobar que el id es de este store
2547

    
2548
        DefaultFeature feature =
2549
            new DefaultFeature(this,
2550
                this.provider.getFeatureProviderByReference(
2551
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2552

    
2553
        if (!this.transforms.isEmpty()) {
2554
            return this.transforms.applyTransform(feature, featureType);
2555
        }
2556
        return feature;
2557
    }
2558

    
2559
    //
2560
    // ====================================================================
2561
    // Gestion de features
2562
    //
2563

    
2564
    private FeatureType fixFeatureType(DefaultFeatureType type)
2565
        throws DataException {
2566
        FeatureType original = this.getDefaultFeatureType();
2567

    
2568
        if ((type == null) || type.equals(original)) {
2569
            return original;
2570
        } else {
2571
            if (!type.isSubtypeOf(original)) {
2572
                Iterator iter = this.getFeatureTypes().iterator();
2573
                FeatureType tmpType;
2574
                boolean found = false;
2575
                while (iter.hasNext()) {
2576
                    tmpType = (FeatureType) iter.next();
2577
                    if (type.equals(tmpType)) {
2578
                        return type;
2579

    
2580
                    } else
2581
                        if (type.isSubtypeOf(tmpType)) {
2582
                            found = true;
2583
                            original = tmpType;
2584
                            break;
2585
                        }
2586

    
2587
                }
2588
                if (!found) {
2589
                    throw new IllegalFeatureTypeException(getName());
2590
                }
2591
            }
2592
        }
2593

    
2594
        // Checks that type has all fields of pk
2595
        // else add the missing attributes at the end.
2596
        if (!original.hasOID()) {
2597
            // Gets original pk attributes
2598
            DefaultEditableFeatureType edOriginal =
2599
                (DefaultEditableFeatureType) original.getEditable();
2600
            FeatureAttributeDescriptor orgAttr;
2601
            Iterator edOriginalIter = edOriginal.iterator();
2602
            while (edOriginalIter.hasNext()) {
2603
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2604
                if (!orgAttr.isPrimaryKey()) {
2605
                    edOriginalIter.remove();
2606
                }
2607
            }
2608

    
2609
            // Checks if all pk attributes are in type
2610
            Iterator typeIterator;
2611
            edOriginalIter = edOriginal.iterator();
2612
            FeatureAttributeDescriptor attr;
2613
            while (edOriginalIter.hasNext()) {
2614
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2615
                typeIterator = type.iterator();
2616
                while (typeIterator.hasNext()) {
2617
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2618
                    if (attr.getName().equals(orgAttr.getName())) {
2619
                        edOriginalIter.remove();
2620
                        break;
2621
                    }
2622
                }
2623
            }
2624

    
2625
            // add missing pk attributes if any
2626
            if (edOriginal.size() > 0) {
2627
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2628
                DefaultEditableFeatureType edType =
2629
                    (DefaultEditableFeatureType) original.getEditable();
2630
                edType.clear();
2631
                edType.addAll(type);
2632
                edType.addAll(edOriginal);
2633
                if (!isEditable) {
2634
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2635
                }
2636
            }
2637

    
2638
        }
2639

    
2640
        return type;
2641
    }
2642

    
2643
    @Override
2644
    public void validateFeatures(int mode) throws DataException {
2645
        FeatureSet collection = null;
2646
        DisposableIterator iter = null;
2647
        try {
2648
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2649
            if( rules==null || rules.isEmpty() ) {
2650
                return;
2651
            }
2652
            checkNotInAppendMode();
2653
            collection = this.getFeatureSet();
2654
            iter = collection.fastIterator();
2655
            long previousVersionOfUpdate = currentVersionOfUpdate();
2656
            while (iter.hasNext()) {
2657
                ((DefaultFeature) iter.next()).validate(mode);
2658
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2659
                    throw new ConcurrentDataModificationException(getName());
2660
                }
2661
            }
2662
        } catch (Exception e) {
2663
            throw new ValidateFeaturesException(e, getName());
2664
        } finally {
2665
            DisposeUtils.disposeQuietly(iter);
2666
            DisposeUtils.disposeQuietly(collection);
2667
        }
2668
    }
2669

    
2670
    @Override
2671
    public FeatureType getDefaultFeatureType() throws DataException {
2672
        try {
2673

    
2674
            if (isEditing()) {
2675
                FeatureType auxFeatureType =
2676
                    featureTypeManager.getType(defaultFeatureType.getId());
2677
                if (auxFeatureType != null) {
2678
                    return avoidEditable(auxFeatureType);
2679
                }
2680
            }
2681
            FeatureType type = this.transforms.getDefaultFeatureType();
2682
                if (type != null) {
2683
                return avoidEditable(type);
2684
                }
2685

    
2686
            return avoidEditable(defaultFeatureType);
2687

    
2688
        } catch (Exception e) {
2689
            throw new GetFeatureTypeException(e, getName());
2690
        }
2691
    }
2692

    
2693
    @Override
2694
    public FeatureType getDefaultFeatureTypeQuietly() {
2695
      try {
2696
        return this.getDefaultFeatureType();
2697
      } catch(Exception ex) {
2698
        return null;
2699
      }
2700
    }
2701
    
2702
    private FeatureType avoidEditable(FeatureType ft) {
2703
        if (ft instanceof EditableFeatureType) {
2704
            return ((EditableFeatureType) ft).getNotEditableCopy();
2705
        } else {
2706
            return ft;
2707
        }
2708
    }
2709

    
2710
    @Override
2711
    public FeatureType getFeatureType(String featureTypeId)
2712
        throws DataException {
2713
        if (featureTypeId == null) {
2714
            return this.getDefaultFeatureType();
2715
        }
2716
        try {
2717
            if (isEditing()) {
2718
                FeatureType auxFeatureType =
2719
                    featureTypeManager.getType(featureTypeId);
2720
                if (auxFeatureType != null) {
2721
                    return auxFeatureType;
2722
                }
2723
            }
2724
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2725
            if (type != null) {
2726
                return type;
2727
            }
2728
            Iterator iter = this.featureTypes.iterator();
2729
            while (iter.hasNext()) {
2730
                type = (FeatureType) iter.next();
2731
                if (type.getId().equals(featureTypeId)) {
2732
                    return type;
2733
                }
2734
            }
2735
            return null;
2736
        } catch (Exception e) {
2737
            throw new GetFeatureTypeException(e, getName());
2738
        }
2739
    }
2740

    
2741
    public FeatureType getProviderDefaultFeatureType() {
2742
        return defaultFeatureType;
2743
    }
2744

    
2745
    @Override
2746
    public List getFeatureTypes() throws DataException {
2747
        try {
2748
            List types;
2749
            if (isEditing()) {
2750
                types = new ArrayList();
2751
                for (FeatureType type : featureTypes) {
2752
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2753
                    if (typeaux != null) {
2754
                        types.add(typeaux);
2755
                    } else {
2756
                        types.add(type);
2757
                    }
2758
                }
2759
                Iterator it = featureTypeManager.newsIterator();
2760
                while (it.hasNext()) {
2761
                    FeatureType type = (FeatureType) it.next();
2762
                    types.add(type);
2763
                }
2764
            } else {
2765
                types = this.transforms.getFeatureTypes();
2766
                if (types == null) {
2767
                    types = featureTypes;
2768
                }
2769
            }
2770
            return Collections.unmodifiableList(types);
2771
        } catch (Exception e) {
2772
            throw new GetFeatureTypeException(e, getName());
2773
        }
2774
    }
2775

    
2776
    public List getProviderFeatureTypes() throws DataException {
2777
        return Collections.unmodifiableList(this.featureTypes);
2778
    }
2779

    
2780
    @Override
2781
    public Feature createFeature(FeatureProvider data) throws DataException {
2782
        DefaultFeature feature = new DefaultFeature(this, data);
2783
        return feature;
2784
    }
2785

    
2786
    public Feature createFeature(FeatureProvider data, FeatureType type)
2787
        throws DataException {
2788
        // FIXME: falta por implementar
2789
        // Comprobar si es un subtipo del feature de data
2790
        // y construir un feature usando el subtipo.
2791
        // Probablemente requiera generar una copia del data.
2792
        throw new NotYetImplemented();
2793
    }
2794

    
2795
    @Override
2796
    public EditableFeature createNewFeature(FeatureType type,
2797
        Feature defaultValues) throws DataException {
2798
        try {
2799
            FeatureProvider data = createNewFeatureProvider(type);
2800
            DefaultEditableFeature feature =
2801
                new DefaultEditableFeature(this, data);
2802
            feature.initializeValues(defaultValues);
2803
            data.setNew(true);
2804

    
2805
            return feature;
2806
        } catch (Exception e) {
2807
            throw new CreateFeatureException(e, getName());
2808
        }
2809
    }
2810

    
2811
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2812
        throws DataException {
2813
        type = this.fixFeatureType((DefaultFeatureType) type);
2814
        FeatureProvider data = this.provider.createFeatureProvider(type);
2815
        data.setNew(true);
2816
        if (type.hasOID() && (data.getOID() == null)) {
2817
            data.setOID(this.provider.createNewOID());
2818
        } else {
2819
            data.setOID(this.getTemporalOID());
2820
        }
2821
        return data;
2822

    
2823
    }
2824

    
2825
    @Override
2826
    public EditableFeature createNewFeature(FeatureType type,
2827
        boolean defaultValues) throws DataException {
2828
        try {
2829
            FeatureProvider data = createNewFeatureProvider(type);
2830
            DefaultEditableFeature feature =
2831
                new DefaultEditableFeature(this, data);
2832
            if (defaultValues) {
2833
                feature.initializeValues();
2834
            }
2835
            return feature;
2836
        } catch (Exception e) {
2837
            throw new CreateFeatureException(e, getName());
2838
        }
2839
    }
2840

    
2841
    @Override
2842
    public EditableFeature createNewFeature(boolean defaultValues)
2843
        throws DataException {
2844
        return this.createNewFeature(this.getDefaultFeatureType(),
2845
            defaultValues);
2846
    }
2847

    
2848
    @Override
2849
    public EditableFeature createNewFeature() throws DataException {
2850
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2851
    }
2852

    
2853
    @Override
2854
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2855
        FeatureType ft = this.getDefaultFeatureType();
2856
        EditableFeature f = this.createNewFeature(ft, false);
2857
        f.copyFrom(defaultValues);
2858
        return f;
2859
    }
2860

    
2861
    @Override
2862
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2863
        FeatureType ft = this.getDefaultFeatureType();
2864
        EditableFeature f = this.createNewFeature(ft, false);
2865
        f.copyFrom(defaultValues);
2866
        return f;
2867
    }
2868

    
2869
    @Override
2870
    public EditableFeatureType createFeatureType() {
2871
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2872
        return ftype;
2873
    }
2874

    
2875
    @Override
2876
    public EditableFeatureType createFeatureType(String id) {
2877
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2878
        return ftype;
2879
    }
2880

    
2881
    //
2882
    // ====================================================================
2883
    // Index related methods
2884
    //
2885

    
2886
    @Override
2887
    public FeatureIndexes getIndexes() {
2888
        return this.indexes;
2889
    }
2890

    
2891
    @Override
2892
    public FeatureIndex createIndex(FeatureType featureType,
2893
        String attributeName, String indexName) throws DataException {
2894
        return createIndex(null, featureType, attributeName, indexName);
2895
    }
2896

    
2897
    @Override
2898
    public FeatureIndex createIndex(String indexTypeName,
2899
        FeatureType featureType, String attributeName, String indexName)
2900
        throws DataException {
2901

    
2902
        return createIndex(indexTypeName, featureType, attributeName,
2903
            indexName, false, null);
2904
    }
2905

    
2906
    @Override
2907
    public FeatureIndex createIndex(FeatureType featureType,
2908
        String attributeName, String indexName, Observer observer)
2909
        throws DataException {
2910
        return createIndex(null, featureType, attributeName, indexName,
2911
            observer);
2912
    }
2913

    
2914
    @Override
2915
    public FeatureIndex createIndex(String indexTypeName,
2916
        FeatureType featureType, String attributeName, String indexName,
2917
        final Observer observer) throws DataException {
2918

    
2919
        return createIndex(indexTypeName, featureType, attributeName,
2920
            indexName, true, observer);
2921
    }
2922

    
2923
    private FeatureIndex createIndex(String indexTypeName,
2924
        FeatureType featureType, String attributeName, String indexName,
2925
        boolean background, final Observer observer) throws DataException {
2926

    
2927
        checkNotInAppendMode();
2928
        FeatureIndexProviderServices index;
2929
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2930
                featureType, indexName,
2931
                featureType.getAttributeDescriptor(attributeName));
2932

    
2933
        try {
2934
            index.fill(background, observer);
2935
        } catch (FeatureIndexException e) {
2936
            throw new InitializeException(index.getName(), e);
2937
        }
2938

    
2939
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2940
        return index;
2941
    }
2942

    
2943
    //
2944
    // ====================================================================
2945
    // Transforms related methods
2946
    //
2947

    
2948
    @Override
2949
    public FeatureStoreTransforms getTransforms() {
2950
        return this.transforms;
2951
    }
2952

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

    
3076
    //
3077
    // ====================================================================
3078
    // UndoRedo related methods
3079
    //
3080

    
3081
    @Override
3082
    public boolean canRedo() {
3083
        return commands.canRedo();
3084
    }
3085

    
3086
    @Override
3087
    public boolean canUndo() {
3088
        return commands.canUndo();
3089
    }
3090

    
3091
    @Override
3092
    public void redo(int num) throws RedoException {
3093
        for (int i = 0; i < num; i++) {
3094
            redo();
3095
        }
3096
    }
3097

    
3098
    @Override
3099
    public void undo(int num) throws UndoException {
3100
        for (int i = 0; i < num; i++) {
3101
            undo();
3102
        }
3103
    }
3104

    
3105
    //
3106
    // ====================================================================
3107
    // Metadata related methods
3108
    //
3109

    
3110
    @Override
3111
    public Object getMetadataID() {
3112
        return this.provider.getSourceId();
3113
    }
3114

    
3115
    @Override
3116
    public void delegate(DynObject dynObject) {
3117
        this.metadata.delegate(dynObject);
3118
    }
3119

    
3120
    @Override
3121
    public DynClass getDynClass() {
3122
        return this.metadata.getDynClass();
3123
    }
3124

    
3125
    @Override
3126
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3127
        try {
3128
            if (this.transforms.hasDynValue(name)) {
3129
                return this.transforms.getDynValue(name);
3130
            }
3131
            if (this.metadata.hasDynValue(name)) {
3132
                return this.metadata.getDynValue(name);
3133
            }
3134
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3135
                return this.provider.getProviderName();
3136
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3137
                return this.provider.getSourceId();
3138
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3139
                try {
3140
                    return this.getDefaultFeatureType();
3141
                } catch (DataException e) {
3142
                    return null;
3143
                }
3144
            }
3145
            return this.metadata.getDynValue(name);
3146
        } catch(Exception ex ) {
3147
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
3148
            return null;
3149
        }
3150
    }
3151

    
3152
    @Override
3153
    public boolean hasDynValue(String name) {
3154
        if (this.transforms.hasDynValue(name)) {
3155
            return true;
3156
        }
3157
        return this.metadata.hasDynValue(name);
3158
    }
3159

    
3160
    @Override
3161
    public boolean hasDynMethod(String name) {
3162
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
3163
    }
3164

    
3165
    @Override
3166
    public void implement(DynClass dynClass) {
3167
        this.metadata.implement(dynClass);
3168
    }
3169

    
3170
    @Override
3171
    public Object invokeDynMethod(String name, Object[] args)
3172
        throws DynMethodException {
3173
        return this.metadata.invokeDynMethod(this, name, args);
3174
    }
3175

    
3176
    @Override
3177
    public Object invokeDynMethod(int code, Object[] args)
3178
        throws DynMethodException {
3179
        return this.metadata.invokeDynMethod(this, code, args);
3180
    }
3181

    
3182
    @Override
3183
    public void setDynValue(String name, Object value)
3184
        throws DynFieldNotFoundException {
3185
                if( this.transforms.hasDynValue(name) ) {
3186
                        this.transforms.setDynValue(name, value);
3187
                        return;
3188
                }
3189
        this.metadata.setDynValue(name, value);
3190

    
3191
    }
3192

    
3193
    /*
3194
     * (non-Javadoc)
3195
     *
3196
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
3197
     */
3198
    @Override
3199
    public Set getMetadataChildren() {
3200
        return this.metadataChildren;
3201
    }
3202

    
3203
    /*
3204
     * (non-Javadoc)
3205
     *
3206
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3207
     */
3208
    @Override
3209
    public String getMetadataName() {
3210
        return this.provider.getProviderName();
3211
    }
3212

    
3213
    public FeatureTypeManager getFeatureTypeManager() {
3214
        return this.featureTypeManager;
3215
    }
3216

    
3217
    @Override
3218
    public long getFeatureCount() throws DataException {
3219
        if (featureCount == null) {
3220
            featureCount = this.provider.getFeatureCount();
3221
        }
3222
        if (this.isEditing()) {
3223
            if(this.isAppending()) {
3224
                try{
3225
                    throw new IllegalStateException();
3226
                } catch(IllegalStateException e) {
3227
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
3228
                }
3229
                return -1;
3230
            } else {
3231
                return featureCount
3232
                    + this.featureManager.getDeltaSize();
3233
            }
3234
        }
3235
        return featureCount;
3236
    }
3237

    
3238
    private Long getTemporalOID() {
3239
        return this.temporalOid++;
3240
    }
3241

    
3242
    @Override
3243
    public FeatureType getProviderFeatureType(String featureTypeId) {
3244
        if (featureTypeId == null) {
3245
            return this.defaultFeatureType;
3246
        }
3247
        FeatureType type;
3248
        Iterator iter = this.featureTypes.iterator();
3249
        while (iter.hasNext()) {
3250
            type = (FeatureType) iter.next();
3251
            if (type.getId().equals(featureTypeId)) {
3252
                return type;
3253
            }
3254
        }
3255
        return null;
3256
    }
3257

    
3258
    @Override
3259
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3260
        return ((DefaultFeature) feature).getData();
3261
    }
3262

    
3263
    @Override
3264
    public DataStore getStore() {
3265
        return this;
3266
    }
3267

    
3268
    @Override
3269
    public FeatureStore getFeatureStore() {
3270
        return this;
3271
    }
3272

    
3273
    @Override
3274
    public void createCache(String name, DynObject parameters)
3275
        throws DataException {
3276
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3277
        if (cache == null) {
3278
            throw new CreateException("FeaureCacheProvider", null);
3279
        }
3280
        cache.apply(this, provider);
3281
        provider = cache;
3282

    
3283
        featureCount = null;
3284
    }
3285

    
3286
    @Override
3287
    public FeatureCache getCache() {
3288
        return cache;
3289
    }
3290

    
3291
    @Override
3292
    public void clear() {
3293
        if (metadata != null) {
3294
            metadata.clear();
3295
        }
3296
    }
3297

    
3298
    @Override
3299
    public String getName() {
3300
        if( this.provider != null ) {
3301
            return this.provider.getName();
3302
        }
3303
        if( this.parameters instanceof HasAFile ) {
3304
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
3305
        }
3306
        return "unknow";
3307
    }
3308

    
3309
    @Override
3310
    public String getFullName() {
3311
        try {
3312
            if( this.provider!=null ) {
3313
                return this.provider.getFullName();
3314
            }
3315
            if( this.parameters instanceof HasAFile ) {
3316
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
3317
            }
3318
            return null;
3319
        } catch(Throwable th) {
3320
            return null;
3321
        }
3322
    }
3323

    
3324
    @Override
3325
    public String getProviderName() {
3326
        if( this.provider!=null ) {
3327
            return this.provider.getProviderName();
3328
        }
3329
        if( this.parameters != null ) {
3330
            return this.parameters.getDataStoreName();
3331
        }
3332
        return null;
3333

    
3334
    }
3335

    
3336
    @Override
3337
    public boolean isKnownEnvelope() {
3338
        return this.provider.isKnownEnvelope();
3339
    }
3340

    
3341
    @Override
3342
    public boolean hasRetrievedFeaturesLimit() {
3343
        return this.provider.hasRetrievedFeaturesLimit();
3344
    }
3345

    
3346
    @Override
3347
    public int getRetrievedFeaturesLimit() {
3348
        return this.provider.getRetrievedFeaturesLimit();
3349
    }
3350

    
3351
    @Override
3352
    public Interval getInterval() {
3353
        if( this.timeSupport!=null ) {
3354
            return this.timeSupport.getInterval();
3355
        }
3356
        try {
3357
            FeatureType type = this.getDefaultFeatureType();
3358
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3359
            if( attr!=null ) {
3360
                Interval interval = attr.getInterval();
3361
                if( interval!=null ) {
3362
                    return interval;
3363
                }
3364
            }
3365
        } catch (DataException ex) {
3366
        }
3367
        return this.provider.getInterval();
3368
    }
3369

    
3370
    @Override
3371
    public Collection getTimes() {
3372
        if( this.timeSupport!=null ) {
3373
            return this.timeSupport.getTimes();
3374
        }
3375
        return this.provider.getTimes();
3376
    }
3377

    
3378
    @Override
3379
    public Collection getTimes(Interval interval) {
3380
        if( this.timeSupport!=null ) {
3381
            return this.timeSupport.getTimes(interval);
3382
        }
3383
        return this.provider.getTimes(interval);
3384
    }
3385

    
3386
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3387
        if( this.isEditing() ) {
3388
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
3389
        }
3390
        if( !this.transforms.isEmpty() ) {
3391
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
3392
        }
3393
        FeatureType ft = this.defaultFeatureType;
3394
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3395
        if( attr == null ) {
3396
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
3397
        }
3398
        EditableFeatureType eft = ft.getEditable();
3399
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3400
        if( attr != null ) {
3401
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
3402
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
3403
            }
3404
            eft.remove(attr.getName());
3405
        }
3406
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3407
            timeSupport.getAttributeName(), 
3408
            timeSupport.getDataType()
3409
        );
3410
        attrTime.setIsTime(true);
3411
        attrTime.setFeatureAttributeEmulator(timeSupport);
3412
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3413
        this.defaultFeatureType = eft.getNotEditableCopy();
3414
        
3415
        this.timeSupport = timeSupport;
3416
    }
3417

    
3418
    @Override
3419
    @SuppressWarnings("CloneDoesntCallSuperClone")
3420
    public Object clone() throws CloneNotSupportedException {
3421

    
3422
        DataStoreParameters dsp = getParameters();
3423

    
3424
        DefaultFeatureStore cloned_store = null;
3425

    
3426
        try {
3427
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3428
                openStore(this.getProviderName(), dsp);
3429
            if (transforms != null) {
3430
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3431
                cloned_store.transforms.setStoreForClone(cloned_store);
3432
            }
3433
        } catch (Exception e) {
3434
            throw new CloneException(e);
3435
        }
3436
        return cloned_store;
3437

    
3438
    }
3439

    
3440
    @Override
3441
    public Feature getFeature(DynObject dynobject) {
3442
        if (dynobject instanceof DynObjectFeatureFacade){
3443
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
3444
            return f;
3445
        }
3446
        return null;
3447
    }
3448

    
3449
    @Override
3450
    public Iterator iterator() {
3451
        FeatureSet fset = null;
3452
        try {
3453
            fset  = this.getFeatureSet();
3454
            return fset.fastIterator();
3455
        } catch (DataException ex) {
3456
            throw new RuntimeException(ex);
3457
        } finally {
3458
            DisposeUtils.disposeQuietly(fset);
3459
        }
3460
    }
3461

    
3462
    @Override
3463
    public long size64() {
3464
        FeatureSet fset = null;
3465
        try {
3466
            fset  = this.getFeatureSet();
3467
            return fset.getSize();
3468
        } catch (DataException ex) {
3469
            throw new RuntimeException(ex);
3470
        } finally {
3471
            DisposeUtils.disposeQuietly(fset);
3472
        }
3473
    }
3474
   
3475
    @Override
3476
    public ExpressionBuilder createExpressionBuilder() {
3477
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3478
        return builder;
3479
    }
3480

    
3481
    @Override
3482
    public ExpressionBuilder createExpression() {
3483
        return createExpressionBuilder();
3484
    }
3485

    
3486
    public FeatureSet features() throws DataException {
3487
        // This is to avoid jython to create a property with this name
3488
        // to access method getFeatures.
3489
        return this.getFeatureSet();
3490
    }
3491

    
3492
    @Override
3493
    public DataStoreProviderFactory getProviderFactory() {
3494
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3495
        return factory;
3496
    }
3497

    
3498
    @Override
3499
    public void useCache(String providerName, DynObject parameters) throws DataException {
3500
        throw new UnsupportedOperationException();
3501
    }
3502

    
3503
    @Override
3504
    public boolean isBroken() {
3505
        return this.state.isBroken();
3506
    }
3507

    
3508
    @Override
3509
    public Throwable getBreakingsCause() {
3510
            return this.state.getBreakingsCause();
3511
    }
3512

    
3513
    @Override
3514
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3515
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3516
      if( !factory.supportNumericOID() ) {
3517
          return null;
3518
      }
3519
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3520
      return wrappedIndex;
3521
  }
3522

    
3523
    @Override
3524
    public FeatureReference getFeatureReference(String code) {
3525
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3526
        return featureReference;
3527
    }
3528

    
3529
    @Override
3530
    public long getPendingChangesCount() {
3531
        if( this.featureManager==null ) {
3532
            return 0;
3533
        }
3534
        return this.featureManager.getPendingChangesCount();
3535
    }
3536

    
3537
    @Override
3538
    public ResourcesStorage getResourcesStorage() {
3539
        ResourcesStorage resourcesStorage;
3540
        try {
3541
            resourcesStorage = this.provider.getResourcesStorage();
3542
            if( resourcesStorage!=null ) {
3543
                return resourcesStorage;
3544
            }
3545
        } catch(Throwable th) {
3546
            
3547
        }
3548
        try {
3549
            DataServerExplorer explorer = this.getExplorer();
3550
            if( explorer==null ) {
3551
                return null;
3552
            }
3553
            resourcesStorage = explorer.getResourcesStorage(this);
3554
            explorer.dispose();
3555
            return resourcesStorage;
3556
        } catch (Exception ex) {
3557
            LOGGER.trace("Can't create resources storage",ex);
3558
            return null;
3559
        }
3560
    }
3561

    
3562
    @Override
3563
    public StoresRepository getStoresRepository() {
3564
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3565
        StoresRepository localRepository = this.provider.getStoresRepository();
3566
        if( localRepository==null ) {
3567
            return mainRepository;
3568
        }
3569
        StoresRepository repository = new BaseStoresRepository(this.getName());
3570
        repository.addRepository(localRepository);
3571
        repository.addRepository(mainRepository);
3572
        return repository;
3573
    }
3574

    
3575
    @Override
3576
    public Feature getSampleFeature() {
3577
            Feature sampleFeature;
3578
            try {
3579
                FeatureSelection theSelection = this.getFeatureSelection();
3580
                if( theSelection!=null && !theSelection.isEmpty() ) {
3581
                    sampleFeature = theSelection.first();
3582
                } else {
3583
                    sampleFeature = this.first();
3584
                }
3585
                if( sampleFeature==null ) {
3586
                    sampleFeature = this.createNewFeature();
3587
                }
3588
            } catch (DataException ex) {
3589
                return null;
3590
            }
3591
            return sampleFeature;
3592
    }
3593

    
3594
    @Override
3595
    public boolean supportReferences() {
3596
        try {
3597
            return this.getDefaultFeatureType().supportReferences();
3598
        } catch (Exception ex) {
3599
            return false;
3600
        }
3601
    }
3602

    
3603
    @Override
3604
    public boolean isTemporary() {
3605
        if( this.provider==null ) {
3606
            return true;
3607
        }
3608
        return this.provider.isTemporary();
3609
    }
3610
    
3611
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3612
        // FIXME this don't work for Store.fType.size() > 1
3613
        FeatureTypeManager manager = this.featureTypeManager;
3614
         if (manager==null) {
3615
             return null;
3616
         }
3617
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3618
         if (originalFeatureType==null) {
3619
             return null;
3620
         }
3621
         return originalFeatureType.getCopy();
3622
    }
3623

    
3624
    @Override
3625
    public Object getProperty(String name) {
3626
        if( this.propertiesSupportHelper==null ) {
3627
            return null;
3628
        }
3629
        return this.propertiesSupportHelper.getProperty(name);
3630
    }
3631

    
3632
    @Override
3633
    public void setProperty(String name, Object value) {
3634
        if( this.propertiesSupportHelper==null ) {
3635
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3636
        }
3637
        this.propertiesSupportHelper.setProperty(name,value);
3638
    }
3639

    
3640
    @Override
3641
    public Map<String, Object> getProperties() {
3642
        if( this.propertiesSupportHelper==null ) {
3643
            return Collections.EMPTY_MAP;
3644
        }
3645
        return this.propertiesSupportHelper.getProperties();
3646
    }
3647
    
3648
    @Override
3649
    public Feature getOriginalFeature(FeatureReference id){
3650
        if(this.featureManager == null){
3651
            return null;
3652
        }
3653
        return featureManager.getOriginal(id);
3654
    }
3655

    
3656
    @Override
3657
    public Feature getOriginalFeature(Feature feature){
3658
        if(feature == null){
3659
            return null;
3660
        }
3661
        return getOriginalFeature(feature.getReference());
3662
    }
3663

    
3664
    @Override
3665
    public boolean isFeatureModified(FeatureReference id){
3666
        if(this.featureManager == null){
3667
            return false;
3668
        }
3669
        return featureManager.isFeatureModified(id);
3670
    }
3671

    
3672
    @Override
3673
    public boolean isFeatureModified(Feature feature){
3674
        if(feature == null){
3675
            return false;
3676
        }
3677
        return isFeatureModified(feature.getReference());
3678
    }
3679

    
3680
    @Override
3681
    public void setTransaction(DataTransaction transaction) {
3682
        this.transaction = transaction;
3683
        if( transaction instanceof DataTransactionServices ) {
3684
            this.provider.setTransaction((DataTransactionServices) transaction);
3685
        }
3686
    }
3687
    
3688
    @Override
3689
    public DataTransaction getTransaction() {
3690
        return transaction;
3691
    }
3692
    
3693
}