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

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

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

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

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

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

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

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

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

    
215
    private DefaultDataManager dataManager = null;
216

    
217
    private FeatureStoreProvider provider = null;
218

    
219
    private DefaultFeatureIndexes indexes;
220

    
221
    private DefaultFeatureStoreTransforms transforms;
222

    
223
    /*friend*/ DelegatedDynObject metadata;
224

    
225
    private Set metadataChildren;
226

    
227
    private Long featureCount = null;
228

    
229
    private long temporalOid = 0;
230

    
231
    private FeatureCacheProvider cache;
232

    
233
    private final StateInformation state;
234

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

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

    
242
        private static final long serialVersionUID = 4109026189635185666L;
243

    
244
        private boolean broken;
245
        private Throwable breakingsCause;
246

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

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

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

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

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

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

    
279

    
280

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

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

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

    
303
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
304

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

    
310
        this.dataManager = (DefaultDataManager) dataManager;
311

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

    
320
    }
321

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
628
        }
629

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

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

    
637
    }
638

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

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

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

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

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

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

    
751
                    }
752

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

    
758

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1044
    }
1045

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

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

    
1055
    }
1056

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

    
1061
    }
1062

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

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

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

    
1081
    }
1082

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

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

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

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

    
1113
    //
1114
    // ====================================================================
1115
    // Edicion
1116
    //
1117

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

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

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

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

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

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

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

    
1158
        }
1159

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

    
1164
        featureCount = null;
1165

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1544
        waitForIndexes();
1545

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

    
1560

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2034
        case MODE_APPEND:
2035
          this.provider.endAppend();
2036
          exitEditingMode();
2037
          invalidateIndexes();
2038
          this.provider.beginAppend();
2039
          hasInserts = false;
2040
          break;
2041

    
2042
        case MODE_FULLEDIT:
2043
          if (hasStrongChanges && !this.allowWrite()) {
2044
            throw new WriteNotAllowedException(getName());
2045
          }
2046
          if (hasStrongChanges) {
2047
            validateFeatures(Feature.FINISH_EDITING);
2048
            provider.performChanges(featureManager.getDeleted(),
2049
              featureManager.getInserted(),
2050
              featureManager.getUpdated(),
2051
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
2052
          }
2053
          invalidateIndexes();
2054
          featureManager = new FeatureManager(this);
2055
          featureTypeManager = new FeatureTypeManager(this);
2056
          spatialManager = new SpatialManager(this, provider.getEnvelope());
2057

    
2058
          commands =
2059
            new DefaultFeatureCommandsStack(this, featureManager,
2060
              spatialManager, featureTypeManager);
2061
          featureCount = null;
2062
          hasStrongChanges = false;
2063
          hasInserts = false;
2064
          break;
2065
        }
2066
      } catch (Exception e) {
2067
        throw new FinishEditingException(e);
2068
      }
2069
    }
2070

    
2071
    @Override
2072
    synchronized public boolean canCommitChanges() throws DataException {
2073
        if ( !this.allowWrite()) {
2074
                return false;
2075
        }
2076
            switch (mode) {
2077
            default:
2078
        case MODE_QUERY:
2079
                return false;
2080

    
2081
        case MODE_APPEND:
2082
                return true;
2083

    
2084
        case MODE_FULLEDIT:
2085
            List types = this.getFeatureTypes();
2086
            for( int i=0; i<types.size(); i++ ) {
2087
                    Object type = types.get(i);
2088
                    if( type instanceof DefaultEditableFeatureType ) {
2089
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
2090
                                    return false;
2091
                            }
2092
                    }
2093
            }
2094
            return true;
2095
            }
2096
    }
2097

    
2098
    @Override
2099
    public void beginEditingGroup(String description)
2100
        throws NeedEditingModeException {
2101
        checkInEditingMode();
2102
        commands.startComplex(description);
2103
    }
2104

    
2105
    @Override
2106
    public void endEditingGroup() throws NeedEditingModeException {
2107
        checkInEditingMode();
2108
        commands.endComplex();
2109
    }
2110

    
2111
    @Override
2112
    public boolean isAppendModeSupported() {
2113
        return this.provider.supportsAppendMode();
2114
    }
2115

    
2116
    @Override
2117
    public void export(DataServerExplorer explorer, String provider,
2118
        NewFeatureStoreParameters params, String name) throws DataException {
2119

    
2120
        if (this.getFeatureTypes().size() != 1) {
2121
            throw new NotYetImplemented(
2122
                "export whith more than one type not yet implemented");
2123
        }
2124
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
2125
        FeatureStore target = null;
2126
        FeatureSet features = null;
2127
        DisposableIterator iterator = null;
2128
        try {
2129
            FeatureType type = this.getDefaultFeatureType();
2130
            if ((params.getDefaultFeatureType() == null)
2131
                || (params.getDefaultFeatureType().size() == 0)) {
2132
                params.setDefaultFeatureType(type.getEditable());
2133

    
2134
            }
2135
            explorer.add(provider, params, true);
2136
            DataManager manager = DALLocator.getDataManager();
2137
            
2138
            DataStoreParameters openParams = explorer.get(name); //OpenFeatureStoreParameters) manager.createStoreParameters(explorer.getProviderName());
2139
//            ToolsLocator.getDynObjectManager().copy(params, openParams);
2140

    
2141
            target = (FeatureStore) manager.openStore(provider, openParams);
2142
            FeatureType targetType = target.getDefaultFeatureType();
2143

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

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

    
2210
    @Override
2211
    public DataSet getDataSet() throws DataException {
2212
        checkNotInAppendMode();
2213
        FeatureQuery query =
2214
            new DefaultFeatureQuery(this.getDefaultFeatureType());
2215
        return new DefaultFeatureSet(this, query);
2216
    }
2217

    
2218
    @Override
2219
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2220
        checkNotInAppendMode();
2221
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2222
    }
2223

    
2224
    @Override
2225
    public void getDataSet(Observer observer) throws DataException {
2226
        checkNotInAppendMode();
2227
        this.getFeatureSet(null, observer);
2228
    }
2229

    
2230
    @Override
2231
    public void getDataSet(DataQuery dataQuery, Observer observer)
2232
        throws DataException {
2233
        checkNotInAppendMode();
2234
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2235
    }
2236

    
2237
    @Override
2238
    public FeatureSet getFeatureSet() throws DataException {
2239
        return this.getFeatureSet((FeatureQuery)null);
2240
    }
2241

    
2242
    @Override
2243
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2244
        throws DataException {
2245
        checkNotInAppendMode();
2246
        if( featureQuery==null ) {
2247
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2248
        }
2249
        return new DefaultFeatureSet(this, featureQuery);
2250
    }
2251

    
2252
    @Override
2253
    public FeatureSet getFeatureSet(String filter) throws DataException {
2254
        return this.getFeatureSet(filter, null, true);
2255
    }
2256

    
2257
    @Override
2258
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2259
        return this.getFeatureSet(filter, sortBy, true);
2260
    }
2261

    
2262
    @Override
2263
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2264
        return this.getFeatureSet(filter, null, true);
2265
    }
2266
    
2267
    @Override
2268
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2269
        return this.getFeatureSet(filter, sortBy, true);
2270
    }
2271

    
2272
    @Override
2273
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2274
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2275
        return this.getFeatureSet(query);
2276
    }
2277
    
2278
    @Override
2279
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2280
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2281
        return this.getFeatureSet(query);
2282
    }
2283
    
2284
    @Override
2285
    public List<Feature> getFeatures(String filter)  {
2286
        return this.getFeatures(filter, null, true);
2287
    }
2288

    
2289
    @Override
2290
    public List<Feature> getFeatures(String filter, String sortBy)  {
2291
        return this.getFeatures(filter, sortBy, true);
2292
    }
2293

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

    
2305
    @Override
2306
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
2307
        return this.getFeatures(filter, sortBy, true);
2308
    }
2309

    
2310
    @Override
2311
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
2312
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2313
        return this.getFeatures(query, 0);
2314
    }
2315
    
2316
    @Override
2317
    public List<Feature> getFeatures(FeatureQuery query)  {
2318
        return this.getFeatures(query, 0);
2319
    }
2320
    
2321
    @Override
2322
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
2323
        try {
2324
            if( pageSize<=0 ) {
2325
                pageSize = 100;
2326
            }
2327
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2328
            return pager.asList();
2329
        } catch (BaseException ex) {
2330
            throw new RuntimeException("Can't create the list of features.", ex);
2331
        }
2332
    }
2333

    
2334
    @Override
2335
    public List<Feature> getFeatures() {
2336
        return this.getFeatures(null, 0);
2337
    }
2338

    
2339
    @Override
2340
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64() {
2341
        return this.getFeatures64(null, 0);
2342
    }
2343

    
2344
    @Override
2345
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter) {
2346
        return this.getFeatures64(filter, null, true);
2347
    }
2348
    
2349
    @Override
2350
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc)  {
2351
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2352
        return this.getFeatures64(query, 0);
2353
    }
2354

    
2355
    @Override
2356
    public GetItemWithSizeIsEmptyAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize)  {
2357
        try {
2358
            if( pageSize<=0 ) {
2359
                pageSize = 100;
2360
            }
2361
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2362
            return pager;
2363
        } catch (BaseException ex) {
2364
            throw new RuntimeException("Can't create the list of features.", ex);
2365
        }
2366
    }
2367

    
2368
    @Override
2369
    public Feature first() throws DataException {
2370
        return this.findFirst((FeatureQuery)null);
2371
    }
2372
    
2373
    @Override
2374
    public Feature findFirst(String filter) throws DataException {
2375
        return this.findFirst(filter, (String)null, true);
2376
    }
2377

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

    
2383
    @Override
2384
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2385
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2386
        return findFirst(query);
2387
    }
2388

    
2389
    @Override
2390
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2391
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2392
        return findFirst(query);
2393
    }
2394
    
2395
    @Override
2396
    public Feature findFirst(Expression filter) throws DataException {
2397
        return this.findFirst(filter, (String)null, true);
2398
    }
2399

    
2400
    @Override
2401
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2402
        return this.findFirst(filter, sortBy, true);
2403
    }
2404

    
2405
    @Override
2406
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2407
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2408
        return findFirst(query);
2409
    }
2410
    
2411
    @Override
2412
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2413
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2414
        return findFirst(query);
2415
    }
2416
    
2417
    @Override
2418
    public Feature findFirst(FeatureQuery query) throws DataException {
2419
        if( query == null ) {
2420
            query = this.createFeatureQuery();
2421
        } else {
2422
            query = query.getCopy();
2423
        }
2424
        query.setLimit(1);
2425
        final MutableObject<Feature> feature = new MutableObject<>();
2426
        try {
2427
            this.accept((Object obj) -> {
2428
                feature.setValue((Feature) obj);
2429
                throw new VisitCanceledException();
2430
            }, query);
2431
        } catch(VisitCanceledException ex) {
2432

    
2433
        } catch(DataException ex) {
2434
            throw ex;
2435
        } catch(Exception ex) {
2436
            throw new RuntimeException("", ex);
2437
        }
2438
        return feature.getValue();
2439
    }
2440

    
2441
    @Override
2442
    public void accept(Visitor visitor) throws BaseException {
2443
        this.accept(visitor, null);
2444
    }
2445

    
2446
    @Override
2447
    public void accept(Visitor visitor, DataQuery dataQuery)
2448
        throws BaseException {
2449
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2450
        try {
2451
            set.accept(visitor);
2452
        } finally {
2453
            set.dispose();
2454
        }
2455
    }
2456

    
2457
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2458
        throws DataException {
2459
        DefaultFeatureType fType =
2460
            (DefaultFeatureType) this.getFeatureType(featureQuery
2461
                .getFeatureTypeId());
2462
        if( featureQuery.hasAttributeNames() || 
2463
            featureQuery.hasConstantsAttributeNames() ||
2464
            fType.hasRequiredFields()    
2465
            ) {
2466
            if( featureQuery.hasGroupByColumns()) {
2467
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2468
            } else {
2469
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2470
            }
2471
        }
2472
        return fType;
2473
    }
2474

    
2475
    @Override
2476
    public void getFeatureSet(Observer observer) throws DataException {
2477
        checkNotInAppendMode();
2478
        this.getFeatureSet(null, observer);
2479
    }
2480

    
2481
    @Override
2482
    public void getFeatureSet(FeatureQuery query, Observer observer)
2483
        throws DataException {
2484
        class LoadInBackGround implements Runnable {
2485

    
2486
            private final FeatureStore store;
2487
            private final FeatureQuery query;
2488
            private final Observer observer;
2489

    
2490
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2491
                Observer observer) {
2492
                this.store = store;
2493
                this.query = query;
2494
                this.observer = observer;
2495
            }
2496

    
2497
            void notify(FeatureStoreNotification theNotification) {
2498
                observer.update(store, theNotification);
2499
            }
2500

    
2501
            @Override
2502
            public void run() {
2503
                FeatureSet set = null;
2504
                try {
2505
                    set = store.getFeatureSet(query);
2506
                    notify(new DefaultFeatureStoreNotification(store,
2507
                        FeatureStoreNotification.LOAD_FINISHED, set));
2508
                } catch (Exception e) {
2509
                    notify(new DefaultFeatureStoreNotification(store,
2510
                        FeatureStoreNotification.LOAD_FINISHED, e));
2511
                } finally {
2512
                    dispose(set);
2513
                }
2514
            }
2515
        }
2516

    
2517
        checkNotInAppendMode();
2518
        if (query == null) {
2519
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2520
        }
2521
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2522
        Thread thread = new Thread(task, "Load Feature Set in background");
2523
        thread.start();
2524
    }
2525

    
2526
    @Override
2527
    public Feature getFeatureByReference(FeatureReference reference)
2528
        throws DataException {
2529
        checkNotInAppendMode();
2530
        FeatureReferenceProviderServices ref = (FeatureReferenceProviderServices) reference;
2531
        FeatureType featureType;
2532
        if (ref.getFeatureTypeId() == null) {
2533
            featureType = this.getDefaultFeatureType();
2534
        } else {
2535
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2536
        }
2537
        return this.getFeatureByReference(reference, featureType);
2538
    }
2539

    
2540
    @Override
2541
    public Feature getFeatureByReference(FeatureReference reference,
2542
        FeatureType featureType) throws DataException {
2543
        checkNotInAppendMode();
2544
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2545
        if (this.mode == MODE_FULLEDIT) {
2546
            Feature f = featureManager.get(reference, this, featureType);
2547
            if (f != null) {
2548
                return f;
2549
            }
2550
        }
2551

    
2552
        FeatureType sourceFeatureType = featureType;
2553
        if (!this.transforms.isEmpty()) {
2554
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2555
        }
2556
        // TODO comprobar que el id es de este store
2557

    
2558
        DefaultFeature feature =
2559
            new DefaultFeature(this,
2560
                this.provider.getFeatureProviderByReference(
2561
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2562

    
2563
        if (!this.transforms.isEmpty()) {
2564
            return this.transforms.applyTransform(feature, featureType);
2565
        }
2566
        return feature;
2567
    }
2568

    
2569
    //
2570
    // ====================================================================
2571
    // Gestion de features
2572
    //
2573

    
2574
    private FeatureType fixFeatureType(DefaultFeatureType type)
2575
        throws DataException {
2576
        FeatureType original = this.getDefaultFeatureType();
2577

    
2578
        if ((type == null) || type.equals(original)) {
2579
            return original;
2580
        } else {
2581
            if (!type.isSubtypeOf(original)) {
2582
                Iterator iter = this.getFeatureTypes().iterator();
2583
                FeatureType tmpType;
2584
                boolean found = false;
2585
                while (iter.hasNext()) {
2586
                    tmpType = (FeatureType) iter.next();
2587
                    if (type.equals(tmpType)) {
2588
                        return type;
2589

    
2590
                    } else
2591
                        if (type.isSubtypeOf(tmpType)) {
2592
                            found = true;
2593
                            original = tmpType;
2594
                            break;
2595
                        }
2596

    
2597
                }
2598
                if (!found) {
2599
                    throw new IllegalFeatureTypeException(getName());
2600
                }
2601
            }
2602
        }
2603

    
2604
        // Checks that type has all fields of pk
2605
        // else add the missing attributes at the end.
2606
        if (!original.hasOID()) {
2607
            // Gets original pk attributes
2608
            DefaultEditableFeatureType edOriginal =
2609
                (DefaultEditableFeatureType) original.getEditable();
2610
            FeatureAttributeDescriptor orgAttr;
2611
            Iterator edOriginalIter = edOriginal.iterator();
2612
            while (edOriginalIter.hasNext()) {
2613
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2614
                if (!orgAttr.isPrimaryKey()) {
2615
                    edOriginalIter.remove();
2616
                }
2617
            }
2618

    
2619
            // Checks if all pk attributes are in type
2620
            Iterator typeIterator;
2621
            edOriginalIter = edOriginal.iterator();
2622
            FeatureAttributeDescriptor attr;
2623
            while (edOriginalIter.hasNext()) {
2624
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2625
                typeIterator = type.iterator();
2626
                while (typeIterator.hasNext()) {
2627
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2628
                    if (attr.getName().equals(orgAttr.getName())) {
2629
                        edOriginalIter.remove();
2630
                        break;
2631
                    }
2632
                }
2633
            }
2634

    
2635
            // add missing pk attributes if any
2636
            if (edOriginal.size() > 0) {
2637
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2638
                DefaultEditableFeatureType edType =
2639
                    (DefaultEditableFeatureType) original.getEditable();
2640
                edType.clear();
2641
                edType.addAll(type);
2642
                edType.addAll(edOriginal);
2643
                if (!isEditable) {
2644
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2645
                }
2646
            }
2647

    
2648
        }
2649

    
2650
        return type;
2651
    }
2652

    
2653
    @Override
2654
    public void validateFeatures(int mode) throws DataException {
2655
        FeatureSet collection = null;
2656
        DisposableIterator iter = null;
2657
        try {
2658
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2659
            if( rules==null || rules.isEmpty() ) {
2660
                return;
2661
            }
2662
            checkNotInAppendMode();
2663
            collection = this.getFeatureSet();
2664
            iter = collection.fastIterator();
2665
            long previousVersionOfUpdate = currentVersionOfUpdate();
2666
            while (iter.hasNext()) {
2667
                ((DefaultFeature) iter.next()).validate(mode);
2668
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2669
                    throw new ConcurrentDataModificationException(getName());
2670
                }
2671
            }
2672
        } catch (Exception e) {
2673
            throw new ValidateFeaturesException(e, getName());
2674
        } finally {
2675
            DisposeUtils.disposeQuietly(iter);
2676
            DisposeUtils.disposeQuietly(collection);
2677
        }
2678
    }
2679

    
2680
    @Override
2681
    public FeatureType getDefaultFeatureType() throws DataException {
2682
        try {
2683

    
2684
            if (isEditing()) {
2685
                FeatureType auxFeatureType =
2686
                    featureTypeManager.getType(defaultFeatureType.getId());
2687
                if (auxFeatureType != null) {
2688
                    return avoidEditable(auxFeatureType);
2689
                }
2690
            }
2691
            FeatureType type = this.transforms.getDefaultFeatureType();
2692
                if (type != null) {
2693
                return avoidEditable(type);
2694
                }
2695

    
2696
            return avoidEditable(defaultFeatureType);
2697

    
2698
        } catch (Exception e) {
2699
            throw new GetFeatureTypeException(e, getName());
2700
        }
2701
    }
2702

    
2703
    @Override
2704
    public FeatureType getDefaultFeatureTypeQuietly() {
2705
      try {
2706
        return this.getDefaultFeatureType();
2707
      } catch(Exception ex) {
2708
        return null;
2709
      }
2710
    }
2711
    
2712
    private FeatureType avoidEditable(FeatureType ft) {
2713
        if (ft instanceof EditableFeatureType) {
2714
            return ((EditableFeatureType) ft).getNotEditableCopy();
2715
        } else {
2716
            return ft;
2717
        }
2718
    }
2719

    
2720
    @Override
2721
    public FeatureType getFeatureType(String featureTypeId)
2722
        throws DataException {
2723
        if (featureTypeId == null) {
2724
            return this.getDefaultFeatureType();
2725
        }
2726
        try {
2727
            if (isEditing()) {
2728
                FeatureType auxFeatureType =
2729
                    featureTypeManager.getType(featureTypeId);
2730
                if (auxFeatureType != null) {
2731
                    return auxFeatureType;
2732
                }
2733
            }
2734
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2735
            if (type != null) {
2736
                return type;
2737
            }
2738
            Iterator iter = this.featureTypes.iterator();
2739
            while (iter.hasNext()) {
2740
                type = (FeatureType) iter.next();
2741
                if (type.getId().equals(featureTypeId)) {
2742
                    return type;
2743
                }
2744
            }
2745
            return null;
2746
        } catch (Exception e) {
2747
            throw new GetFeatureTypeException(e, getName());
2748
        }
2749
    }
2750

    
2751
    public FeatureType getProviderDefaultFeatureType() {
2752
        return defaultFeatureType;
2753
    }
2754

    
2755
    @Override
2756
    public List getFeatureTypes() throws DataException {
2757
        try {
2758
            List types;
2759
            if (isEditing()) {
2760
                types = new ArrayList();
2761
                for (FeatureType type : featureTypes) {
2762
                    FeatureType typeaux = featureTypeManager.getType(type.getId());
2763
                    if (typeaux != null) {
2764
                        types.add(typeaux);
2765
                    } else {
2766
                        types.add(type);
2767
                    }
2768
                }
2769
                Iterator it = featureTypeManager.newsIterator();
2770
                while (it.hasNext()) {
2771
                    FeatureType type = (FeatureType) it.next();
2772
                    types.add(type);
2773
                }
2774
            } else {
2775
                types = this.transforms.getFeatureTypes();
2776
                if (types == null) {
2777
                    types = featureTypes;
2778
                }
2779
            }
2780
            return Collections.unmodifiableList(types);
2781
        } catch (Exception e) {
2782
            throw new GetFeatureTypeException(e, getName());
2783
        }
2784
    }
2785

    
2786
    public List getProviderFeatureTypes() throws DataException {
2787
        return Collections.unmodifiableList(this.featureTypes);
2788
    }
2789

    
2790
    @Override
2791
    public Feature createFeature(FeatureProvider data) throws DataException {
2792
        DefaultFeature feature = new DefaultFeature(this, data);
2793
        return feature;
2794
    }
2795

    
2796
    public Feature createFeature(FeatureProvider data, FeatureType type)
2797
        throws DataException {
2798
        // FIXME: falta por implementar
2799
        // Comprobar si es un subtipo del feature de data
2800
        // y construir un feature usando el subtipo.
2801
        // Probablemente requiera generar una copia del data.
2802
        throw new NotYetImplemented();
2803
    }
2804

    
2805
    @Override
2806
    public EditableFeature createNewFeature(FeatureType type,
2807
        Feature defaultValues) throws DataException {
2808
        try {
2809
            FeatureProvider data = createNewFeatureProvider(type);
2810
            DefaultEditableFeature feature =
2811
                new DefaultEditableFeature(this, data);
2812
            feature.initializeValues(defaultValues);
2813
            data.setNew(true);
2814

    
2815
            return feature;
2816
        } catch (Exception e) {
2817
            throw new CreateFeatureException(e, getName());
2818
        }
2819
    }
2820

    
2821
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2822
        throws DataException {
2823
        type = this.fixFeatureType((DefaultFeatureType) type);
2824
        FeatureProvider data = this.provider.createFeatureProvider(type);
2825
        data.setNew(true);
2826
        if (type.hasOID() && (data.getOID() == null)) {
2827
            data.setOID(this.provider.createNewOID());
2828
        } else {
2829
            data.setOID(this.getTemporalOID());
2830
        }
2831
        return data;
2832

    
2833
    }
2834

    
2835
    @Override
2836
    public EditableFeature createNewFeature(FeatureType type,
2837
        boolean defaultValues) throws DataException {
2838
        try {
2839
            FeatureProvider data = createNewFeatureProvider(type);
2840
            DefaultEditableFeature feature =
2841
                new DefaultEditableFeature(this, data);
2842
            if (defaultValues) {
2843
                feature.initializeValues();
2844
            }
2845
            return feature;
2846
        } catch (Exception e) {
2847
            throw new CreateFeatureException(e, getName());
2848
        }
2849
    }
2850

    
2851
    @Override
2852
    public EditableFeature createNewFeature(boolean defaultValues)
2853
        throws DataException {
2854
        return this.createNewFeature(this.getDefaultFeatureType(),
2855
            defaultValues);
2856
    }
2857

    
2858
    @Override
2859
    public EditableFeature createNewFeature() throws DataException {
2860
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2861
    }
2862

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

    
2871
    @Override
2872
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2873
        FeatureType ft = this.getDefaultFeatureType();
2874
        EditableFeature f = this.createNewFeature(ft, false);
2875
        f.copyFrom(defaultValues);
2876
        return f;
2877
    }
2878

    
2879
    @Override
2880
    public EditableFeatureType createFeatureType() {
2881
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2882
        return ftype;
2883
    }
2884

    
2885
    @Override
2886
    public EditableFeatureType createFeatureType(String id) {
2887
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2888
        return ftype;
2889
    }
2890

    
2891
    //
2892
    // ====================================================================
2893
    // Index related methods
2894
    //
2895

    
2896
    @Override
2897
    public FeatureIndexes getIndexes() {
2898
        return this.indexes;
2899
    }
2900

    
2901
    @Override
2902
    public FeatureIndex createIndex(FeatureType featureType,
2903
        String attributeName, String indexName) throws DataException {
2904
        return createIndex(null, featureType, attributeName, indexName);
2905
    }
2906

    
2907
    @Override
2908
    public FeatureIndex createIndex(String indexTypeName,
2909
        FeatureType featureType, String attributeName, String indexName)
2910
        throws DataException {
2911

    
2912
        return createIndex(indexTypeName, featureType, attributeName,
2913
            indexName, false, null);
2914
    }
2915

    
2916
    @Override
2917
    public FeatureIndex createIndex(FeatureType featureType,
2918
        String attributeName, String indexName, Observer observer)
2919
        throws DataException {
2920
        return createIndex(null, featureType, attributeName, indexName,
2921
            observer);
2922
    }
2923

    
2924
    @Override
2925
    public FeatureIndex createIndex(String indexTypeName,
2926
        FeatureType featureType, String attributeName, String indexName,
2927
        final Observer observer) throws DataException {
2928

    
2929
        return createIndex(indexTypeName, featureType, attributeName,
2930
            indexName, true, observer);
2931
    }
2932

    
2933
    private FeatureIndex createIndex(String indexTypeName,
2934
        FeatureType featureType, String attributeName, String indexName,
2935
        boolean background, final Observer observer) throws DataException {
2936

    
2937
        checkNotInAppendMode();
2938
        FeatureIndexProviderServices index;
2939
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2940
                featureType, indexName,
2941
                featureType.getAttributeDescriptor(attributeName));
2942

    
2943
        try {
2944
            index.fill(background, observer);
2945
        } catch (FeatureIndexException e) {
2946
            throw new InitializeException(index.getName(), e);
2947
        }
2948

    
2949
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2950
        return index;
2951
    }
2952

    
2953
    //
2954
    // ====================================================================
2955
    // Transforms related methods
2956
    //
2957

    
2958
    @Override
2959
    public FeatureStoreTransforms getTransforms() {
2960
        return this.transforms;
2961
    }
2962

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

    
3086
    //
3087
    // ====================================================================
3088
    // UndoRedo related methods
3089
    //
3090

    
3091
    @Override
3092
    public boolean canRedo() {
3093
        return commands.canRedo();
3094
    }
3095

    
3096
    @Override
3097
    public boolean canUndo() {
3098
        return commands.canUndo();
3099
    }
3100

    
3101
    @Override
3102
    public void redo(int num) throws RedoException {
3103
        for (int i = 0; i < num; i++) {
3104
            redo();
3105
        }
3106
    }
3107

    
3108
    @Override
3109
    public void undo(int num) throws UndoException {
3110
        for (int i = 0; i < num; i++) {
3111
            undo();
3112
        }
3113
    }
3114

    
3115
    //
3116
    // ====================================================================
3117
    // Metadata related methods
3118
    //
3119

    
3120
    @Override
3121
    public Object getMetadataID() {
3122
        return this.provider.getSourceId();
3123
    }
3124

    
3125
    @Override
3126
    public void delegate(DynObject dynObject) {
3127
        this.metadata.delegate(dynObject);
3128
    }
3129

    
3130
    @Override
3131
    public DynClass getDynClass() {
3132
        return this.metadata.getDynClass();
3133
    }
3134

    
3135
    @Override
3136
    public Object getDynValue(String name) throws DynFieldNotFoundException {
3137
        try {
3138
            if (this.transforms.hasDynValue(name)) {
3139
                return this.transforms.getDynValue(name);
3140
            }
3141
            if (this.metadata.hasDynValue(name)) {
3142
                return this.metadata.getDynValue(name);
3143
            }
3144
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
3145
                return this.provider.getProviderName();
3146
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
3147
                return this.provider.getSourceId();
3148
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
3149
                try {
3150
                    return this.getDefaultFeatureType();
3151
                } catch (DataException e) {
3152
                    return null;
3153
                }
3154
            }
3155
            return this.metadata.getDynValue(name);
3156
        } catch(Exception ex ) {
3157
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
3158
            return null;
3159
        }
3160
    }
3161

    
3162
    @Override
3163
    public boolean hasDynValue(String name) {
3164
        if (this.transforms.hasDynValue(name)) {
3165
            return true;
3166
        }
3167
        return this.metadata.hasDynValue(name);
3168
    }
3169

    
3170
    @Override
3171
    public boolean hasDynMethod(String name) {
3172
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
3173
    }
3174

    
3175
    @Override
3176
    public void implement(DynClass dynClass) {
3177
        this.metadata.implement(dynClass);
3178
    }
3179

    
3180
    @Override
3181
    public Object invokeDynMethod(String name, Object[] args)
3182
        throws DynMethodException {
3183
        return this.metadata.invokeDynMethod(this, name, args);
3184
    }
3185

    
3186
    @Override
3187
    public Object invokeDynMethod(int code, Object[] args)
3188
        throws DynMethodException {
3189
        return this.metadata.invokeDynMethod(this, code, args);
3190
    }
3191

    
3192
    @Override
3193
    public void setDynValue(String name, Object value)
3194
        throws DynFieldNotFoundException {
3195
                if( this.transforms.hasDynValue(name) ) {
3196
                        this.transforms.setDynValue(name, value);
3197
                        return;
3198
                }
3199
        this.metadata.setDynValue(name, value);
3200

    
3201
    }
3202

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

    
3213
    /*
3214
     * (non-Javadoc)
3215
     *
3216
     * @see org.gvsig.metadata.Metadata#getMetadataName()
3217
     */
3218
    @Override
3219
    public String getMetadataName() {
3220
        return this.provider.getProviderName();
3221
    }
3222

    
3223
    public FeatureTypeManager getFeatureTypeManager() {
3224
        return this.featureTypeManager;
3225
    }
3226

    
3227
    @Override
3228
    public long getFeatureCount() throws DataException {
3229
        if (featureCount == null) {
3230
            featureCount = this.provider.getFeatureCount();
3231
        }
3232
        if (this.isEditing()) {
3233
            if(this.isAppending()) {
3234
                try{
3235
                    throw new IllegalStateException();
3236
                } catch(IllegalStateException e) {
3237
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
3238
                }
3239
                return -1;
3240
            } else {
3241
                return featureCount
3242
                    + this.featureManager.getDeltaSize();
3243
            }
3244
        }
3245
        return featureCount;
3246
    }
3247

    
3248
    private Long getTemporalOID() {
3249
        return this.temporalOid++;
3250
    }
3251

    
3252
    @Override
3253
    public FeatureType getProviderFeatureType(String featureTypeId) {
3254
        if (featureTypeId == null) {
3255
            return this.defaultFeatureType;
3256
        }
3257
        FeatureType type;
3258
        Iterator iter = this.featureTypes.iterator();
3259
        while (iter.hasNext()) {
3260
            type = (FeatureType) iter.next();
3261
            if (type.getId().equals(featureTypeId)) {
3262
                return type;
3263
            }
3264
        }
3265
        return null;
3266
    }
3267

    
3268
    @Override
3269
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3270
        return ((DefaultFeature) feature).getData();
3271
    }
3272

    
3273
    @Override
3274
    public DataStore getStore() {
3275
        return this;
3276
    }
3277

    
3278
    @Override
3279
    public FeatureStore getFeatureStore() {
3280
        return this;
3281
    }
3282

    
3283
    @Override
3284
    public void createCache(String name, DynObject parameters)
3285
        throws DataException {
3286
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3287
        if (cache == null) {
3288
            throw new CreateException("FeaureCacheProvider", null);
3289
        }
3290
        cache.apply(this, provider);
3291
        provider = cache;
3292

    
3293
        featureCount = null;
3294
    }
3295

    
3296
    @Override
3297
    public FeatureCache getCache() {
3298
        return cache;
3299
    }
3300

    
3301
    @Override
3302
    public void clear() {
3303
        if (metadata != null) {
3304
            metadata.clear();
3305
        }
3306
    }
3307

    
3308
    @Override
3309
    public String getName() {
3310
        if( this.provider != null ) {
3311
            return this.provider.getName();
3312
        }
3313
        if( this.parameters instanceof HasAFile ) {
3314
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
3315
        }
3316
        return "unknow";
3317
    }
3318

    
3319
    @Override
3320
    public String getFullName() {
3321
        try {
3322
            if( this.provider!=null ) {
3323
                return this.provider.getFullName();
3324
            }
3325
            if( this.parameters instanceof HasAFile ) {
3326
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
3327
            }
3328
            return null;
3329
        } catch(Throwable th) {
3330
            return null;
3331
        }
3332
    }
3333

    
3334
    @Override
3335
    public String getProviderName() {
3336
        if( this.provider!=null ) {
3337
            return this.provider.getProviderName();
3338
        }
3339
        if( this.parameters != null ) {
3340
            return this.parameters.getDataStoreName();
3341
        }
3342
        return null;
3343

    
3344
    }
3345

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

    
3351
    @Override
3352
    public boolean hasRetrievedFeaturesLimit() {
3353
        return this.provider.hasRetrievedFeaturesLimit();
3354
    }
3355

    
3356
    @Override
3357
    public int getRetrievedFeaturesLimit() {
3358
        return this.provider.getRetrievedFeaturesLimit();
3359
    }
3360

    
3361
    @Override
3362
    public Interval getInterval() {
3363
        if( this.timeSupport!=null ) {
3364
            return this.timeSupport.getInterval();
3365
        }
3366
        try {
3367
            FeatureType type = this.getDefaultFeatureType();
3368
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3369
            if( attr!=null ) {
3370
                Interval interval = attr.getInterval();
3371
                if( interval!=null ) {
3372
                    return interval;
3373
                }
3374
            }
3375
        } catch (DataException ex) {
3376
        }
3377
        return this.provider.getInterval();
3378
    }
3379

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

    
3388
    @Override
3389
    public Collection getTimes(Interval interval) {
3390
        if( this.timeSupport!=null ) {
3391
            return this.timeSupport.getTimes(interval);
3392
        }
3393
        return this.provider.getTimes(interval);
3394
    }
3395

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

    
3428
    @Override
3429
    @SuppressWarnings("CloneDoesntCallSuperClone")
3430
    public Object clone() throws CloneNotSupportedException {
3431

    
3432
        DataStoreParameters dsp = getParameters();
3433

    
3434
        DefaultFeatureStore cloned_store = null;
3435

    
3436
        try {
3437
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3438
                openStore(this.getProviderName(), dsp);
3439
            if (transforms != null) {
3440
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3441
                cloned_store.transforms.setStoreForClone(cloned_store);
3442
            }
3443
        } catch (Exception e) {
3444
            throw new CloneException(e);
3445
        }
3446
        return cloned_store;
3447

    
3448
    }
3449

    
3450
    @Override
3451
    public Feature getFeature(DynObject dynobject) {
3452
        if (dynobject instanceof DynObjectFeatureFacade){
3453
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
3454
            return f;
3455
        }
3456
        return null;
3457
    }
3458

    
3459
    @Override
3460
    public Iterator iterator() {
3461
        FeatureSet fset = null;
3462
        try {
3463
            fset  = this.getFeatureSet();
3464
            return fset.fastIterator();
3465
        } catch (DataException ex) {
3466
            throw new RuntimeException(ex);
3467
        } finally {
3468
            DisposeUtils.disposeQuietly(fset);
3469
        }
3470
    }
3471

    
3472
    @Override
3473
    public long size64() {
3474
        FeatureSet fset = null;
3475
        try {
3476
            fset  = this.getFeatureSet();
3477
            return fset.getSize();
3478
        } catch (DataException ex) {
3479
            throw new RuntimeException(ex);
3480
        } finally {
3481
            DisposeUtils.disposeQuietly(fset);
3482
        }
3483
    }
3484
   
3485
    @Override
3486
    public ExpressionBuilder createExpressionBuilder() {
3487
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3488
        return builder;
3489
    }
3490

    
3491
    @Override
3492
    public ExpressionBuilder createExpression() {
3493
        return createExpressionBuilder();
3494
    }
3495

    
3496
    public FeatureSet features() throws DataException {
3497
        // This is to avoid jython to create a property with this name
3498
        // to access method getFeatures.
3499
        return this.getFeatureSet();
3500
    }
3501

    
3502
    @Override
3503
    public DataStoreProviderFactory getProviderFactory() {
3504
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3505
        return factory;
3506
    }
3507

    
3508
    @Override
3509
    public void useCache(String providerName, DynObject parameters) throws DataException {
3510
        throw new UnsupportedOperationException();
3511
    }
3512

    
3513
    @Override
3514
    public boolean isBroken() {
3515
        return this.state.isBroken();
3516
    }
3517

    
3518
    @Override
3519
    public Throwable getBreakingsCause() {
3520
            return this.state.getBreakingsCause();
3521
    }
3522

    
3523
    @Override
3524
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3525
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3526
      if( !factory.supportNumericOID() ) {
3527
          return null;
3528
      }
3529
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3530
      return wrappedIndex;
3531
  }
3532

    
3533
    @Override
3534
    public FeatureReference getFeatureReference(String code) {
3535
        FeatureReference featureReference = FeatureReferenceFactory.createFromCode(this, code);
3536
        return featureReference;
3537
    }
3538

    
3539
    @Override
3540
    public long getPendingChangesCount() {
3541
        if( this.featureManager==null ) {
3542
            return 0;
3543
        }
3544
        return this.featureManager.getPendingChangesCount();
3545
    }
3546

    
3547
    @Override
3548
    public ResourcesStorage getResourcesStorage() {
3549
        ResourcesStorage resourcesStorage;
3550
        try {
3551
            resourcesStorage = this.provider.getResourcesStorage();
3552
            if( resourcesStorage!=null ) {
3553
                return resourcesStorage;
3554
            }
3555
        } catch(Throwable th) {
3556
            
3557
        }
3558
        try {
3559
            DataServerExplorer explorer = this.getExplorer();
3560
            if( explorer==null ) {
3561
                return null;
3562
            }
3563
            resourcesStorage = explorer.getResourcesStorage(this);
3564
            explorer.dispose();
3565
            return resourcesStorage;
3566
        } catch (Exception ex) {
3567
            LOGGER.trace("Can't create resources storage",ex);
3568
            return null;
3569
        }
3570
    }
3571

    
3572
    @Override
3573
    public StoresRepository getStoresRepository() {
3574
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3575
        StoresRepository localRepository = this.provider.getStoresRepository();
3576
        if( localRepository==null ) {
3577
            return mainRepository;
3578
        }
3579
        StoresRepository repository = new BaseStoresRepository(this.getName());
3580
        repository.addRepository(localRepository);
3581
        repository.addRepository(mainRepository);
3582
        return repository;
3583
    }
3584

    
3585
    @Override
3586
    public Feature getSampleFeature() {
3587
            Feature sampleFeature;
3588
            try {
3589
                FeatureSelection theSelection = this.getFeatureSelection();
3590
                if( theSelection!=null && !theSelection.isEmpty() ) {
3591
                    sampleFeature = theSelection.first();
3592
                } else {
3593
                    sampleFeature = this.first();
3594
                }
3595
                if( sampleFeature==null ) {
3596
                    sampleFeature = this.createNewFeature();
3597
                }
3598
            } catch (DataException ex) {
3599
                return null;
3600
            }
3601
            return sampleFeature;
3602
    }
3603

    
3604
    @Override
3605
    public boolean supportReferences() {
3606
        try {
3607
            return this.getDefaultFeatureType().supportReferences();
3608
        } catch (Exception ex) {
3609
            return false;
3610
        }
3611
    }
3612

    
3613
    @Override
3614
    public boolean isTemporary() {
3615
        if( this.provider==null ) {
3616
            return true;
3617
        }
3618
        return this.provider.isTemporary();
3619
    }
3620
    
3621
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3622
        // FIXME this don't work for Store.fType.size() > 1
3623
        FeatureTypeManager manager = this.featureTypeManager;
3624
         if (manager==null) {
3625
             return null;
3626
         }
3627
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3628
         if (originalFeatureType==null) {
3629
             return null;
3630
         }
3631
         return originalFeatureType.getCopy();
3632
    }
3633

    
3634
    @Override
3635
    public Object getProperty(String name) {
3636
        if( this.propertiesSupportHelper==null ) {
3637
            return null;
3638
        }
3639
        return this.propertiesSupportHelper.getProperty(name);
3640
    }
3641

    
3642
    @Override
3643
    public void setProperty(String name, Object value) {
3644
        if( this.propertiesSupportHelper==null ) {
3645
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3646
        }
3647
        this.propertiesSupportHelper.setProperty(name,value);
3648
    }
3649

    
3650
    @Override
3651
    public Map<String, Object> getProperties() {
3652
        if( this.propertiesSupportHelper==null ) {
3653
            return Collections.EMPTY_MAP;
3654
        }
3655
        return this.propertiesSupportHelper.getProperties();
3656
    }
3657
    
3658
    @Override
3659
    public Feature getOriginalFeature(FeatureReference id){
3660
        if(this.featureManager == null){
3661
            return null;
3662
        }
3663
        return featureManager.getOriginal(id);
3664
    }
3665

    
3666
    @Override
3667
    public Feature getOriginalFeature(Feature feature){
3668
        if(feature == null){
3669
            return null;
3670
        }
3671
        return getOriginalFeature(feature.getReference());
3672
    }
3673

    
3674
    @Override
3675
    public boolean isFeatureModified(FeatureReference id){
3676
        if(this.featureManager == null){
3677
            return false;
3678
        }
3679
        return featureManager.isFeatureModified(id);
3680
    }
3681

    
3682
    @Override
3683
    public boolean isFeatureModified(Feature feature){
3684
        if(feature == null){
3685
            return false;
3686
        }
3687
        return isFeatureModified(feature.getReference());
3688
    }
3689

    
3690
    @Override
3691
    public void setTransaction(DataTransaction transaction) {
3692
        this.transaction = transaction;
3693
        if( transaction instanceof DataTransactionServices ) {
3694
            this.provider.setTransaction((DataTransactionServices) transaction);
3695
        }
3696
    }
3697
    
3698
    @Override
3699
    public DataTransaction getTransaction() {
3700
        return transaction;
3701
    }
3702
    
3703
}