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

History | View | Annotate | Download (106 KB)

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

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

    
27
import org.gvsig.fmap.dal.feature.impl.editing.memory.SpatialManager;
28
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureTypeManager;
29
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureManager;
30

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

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

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

    
176
@SuppressWarnings("UseSpecificCatch")
177
public class DefaultFeatureStore extends AbstractDataStore implements
178
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
179

    
180
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
181

    
182
    private DataStoreParameters parameters = null;
183
    private FeatureSelection selection;
184
    private FeatureLocks locks;
185

    
186
    private DelegateWeakReferencingObservable delegateObservable =
187
        new DelegateWeakReferencingObservable(this);
188

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

    
198
    private FeatureType defaultFeatureType = null;
199
    private List<FeatureType> featureTypes = new ArrayList<>();
200

    
201
    private int mode = MODE_QUERY;
202
    private long versionOfUpdate = 0;
203
    private boolean hasStrongChanges = true;
204
    private boolean hasInserts = true;
205

    
206
    private DefaultDataManager dataManager = null;
207

    
208
    private FeatureStoreProvider provider = null;
209

    
210
    private DefaultFeatureIndexes indexes;
211

    
212
    private DefaultFeatureStoreTransforms transforms;
213

    
214
    DelegatedDynObject metadata;
215

    
216
    private Set metadataChildren;
217

    
218
    private Long featureCount = null;
219

    
220
    private long temporalOid = 0;
221

    
222
    private FeatureCacheProvider cache;
223

    
224
    StateInformation state;
225

    
226
    FeatureStoreTimeSupport timeSupport;
227

    
228

    
229
    private class StateInformation extends HashMap<Object, Object> {
230

    
231
        private static final long serialVersionUID = 4109026189635185666L;
232

    
233
        private boolean broken;
234
        private Throwable breakingsCause;
235

    
236
        @SuppressWarnings("OverridableMethodCallInConstructor")
237
        public StateInformation() {
238
            this.clear();
239
        }
240

    
241
        @Override
242
        public void clear() {
243
            this.broken = false;
244
            this.breakingsCause = null;
245
            super.clear();
246
        }
247

    
248
        public boolean isBroken() {
249
            return this.broken;
250
        }
251

    
252
        public void broken() {
253
            this.broken = true;
254
        }
255

    
256
        public Throwable getBreakingsCause() {
257
            return this.breakingsCause;
258
        }
259

    
260
        public void setBreakingsCause(Throwable cause) {
261
            if( this.breakingsCause==null ) {
262
                this.breakingsCause = cause;
263
            }
264
            this.broken = true;
265
        }
266
    }
267

    
268

    
269

    
270
    /*
271
     * TODO:
272
     *
273
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
274
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
275
     * featureType al que se le han cambiado las reglas de validacion cuando
276
     * hasStrongChanges=false.
277
     */
278

    
279
    public DefaultFeatureStore() {
280
        this.state = new StateInformation();
281
    }
282
    
283
    @Override
284
    protected DataManager getDataManager() {
285
        return this.dataManager;
286
    }
287

    
288
    @Override
289
    public void intialize(DataManager dataManager,
290
        DataStoreParameters parameters) throws InitializeException {
291

    
292
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
293

    
294
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
295
            FeatureStore.METADATA_DEFINITION_NAME,
296
            MetadataManager.METADATA_NAMESPACE
297
        );
298

    
299
        this.dataManager = (DefaultDataManager) dataManager;
300

    
301
        this.parameters = parameters;
302
        this.transforms = new DefaultFeatureStoreTransforms(this);
303
        try {
304
            indexes = new DefaultFeatureIndexes(this);
305
        } catch (DataException e) {
306
            throw new InitializeException(e);
307
        }
308

    
309
    }
310

    
311
    @Override
312
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
313
        this.provider = (FeatureStoreProvider) provider;
314
        this.delegate((DynObject) provider);
315
        this.metadataChildren = new HashSet();
316
        this.metadataChildren.add(provider);
317
        loadDALFile();
318
    }
319

    
320
    @Override
321
    public DataStoreParameters getParameters() {
322
        if( this.parameters==null ) {
323
            LOGGER.warn("Store parametes are null");
324
        }
325
        return parameters;
326
    }
327

    
328
    public int getMode() {
329
        return this.mode;
330
    }
331

    
332
    @Override
333
    public DataManager getManager() {
334
        return this.dataManager;
335
    }
336

    
337
    @Override
338
    public UnmodifiableBasicMap<String,DataStore> getChildren() {
339
        UnmodifiableBasicMap<String, DataStore> children = this.provider.getChildren();
340
        if( children == null ) {
341
            return UnmodifiableBasicMap.EMPTY_UNMODIFIABLEBASICMAP;
342
        }
343
        return children;
344
    }
345

    
346
    @Override
347
    public FeatureStoreProvider getProvider() {
348
        return this.provider;
349
    }
350

    
351
    public FeatureManager getFeatureManager() {
352
        return this.featureManager;
353
    }
354

    
355
    @Override
356
    public void setFeatureTypes(List types, FeatureType defaultType) {
357
        this.featureTypes = types;
358
        this.defaultFeatureType = defaultType;
359
    }
360

    
361
    public void open() throws OpenException {
362
        if (this.mode != MODE_QUERY) {
363
            // TODO: Se puede hacer un open estando en edicion ?
364
            try {
365
                throw new IllegalStateException();
366
            } catch(Exception ex) {
367
                LOGGER.warn("Opening a store in editing/append mode ("+this.getFullName()+").",ex);
368
            }
369
        }
370
        this.notifyChange(DataStoreNotification.BEFORE_OPEN);
371
        this.provider.open();
372
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
373
    }
374

    
375
    @Override
376
    public void refresh() throws OpenException, InitializeException {
377
        if (this.mode != MODE_QUERY) {
378
            throw new IllegalStateException();
379
        }
380
        this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH);
381
        if( state.isBroken() ) {
382
            this.load(state);
383
        } else {
384
            this.featureCount = null;
385
            this.provider.refresh();
386
        }
387
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
388
    }
389

    
390
    public void close() throws CloseException {
391
        if (this.mode != MODE_QUERY) {
392
            // TODO: Se puede hacer un close estando en edicion ?
393
            try {
394
                throw new IllegalStateException();
395
            } catch(Exception ex) {
396
                LOGGER.warn("Clossing a store in editing/append mode ("+this.getFullName()+").",ex);
397
            }
398
        }
399
        this.notifyChange(DataStoreNotification.BEFORE_CLOSE);
400
        this.featureCount = null;
401
        this.provider.close();
402
        this.notifyChange(DataStoreNotification.AFTER_CLOSE);
403
    }
404

    
405
    @Override
406
    protected void doDispose() throws BaseException {
407
        if (this.mode != MODE_QUERY) {
408
            // TODO: Se puede hacer un dispose estando en edicion ?
409
            try {
410
                throw new IllegalStateException();
411
            } catch(Exception ex) {
412
                LOGGER.warn("Dispossing a store in editing/append mode ("+this.getFullName()+").",ex);
413
            }
414
        }
415
        this.notifyChange(DataStoreNotification.BEFORE_DISPOSE);
416
        this.disposeIndexes();
417
        if( this.provider!=null ) {
418
            this.provider.dispose();
419
        }
420
        if (this.selection != null) {
421
            this.selection.dispose();
422
            this.selection = null;
423
        }
424
        this.commands = null;
425
        this.featureCount = null;
426
        if (this.locks != null) {
427
            // this.locks.dispose();
428
            this.locks = null;
429
        }
430

    
431
        if (this.featureTypeManager != null) {
432
            this.featureTypeManager.dispose();
433
            this.featureTypeManager = null;
434
        }
435

    
436
        this.featureManager = null;
437
        this.spatialManager = null;
438

    
439
        this.parameters = null;
440
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
441
        if (delegateObservable != null) {
442
            this.delegateObservable.deleteObservers();
443
            this.delegateObservable = null;
444
        }
445
    }
446

    
447
    @Override
448
    public boolean allowWrite() {
449
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
450
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
451
            return false;
452
        }
453
        return this.provider.allowWrite();
454
    }
455

    
456
    @Override
457
    public boolean canWriteGeometry(int geometryType) throws DataException {
458
        return this.provider.canWriteGeometry(geometryType, 0);
459
    }
460

    
461
    @Override
462
    public DataServerExplorer getExplorer() throws ReadException,
463
        ValidateDataParametersException {
464
        if( this.state.isBroken() ) {
465
            try {
466
                return this.provider.getExplorer();
467
            } catch(Throwable th) {
468
                return null;
469
            }
470
        } else {
471
            return this.provider.getExplorer();
472
        }
473
    }
474

    
475
    /*
476
     * public Metadata getMetadata() throws MetadataNotFoundException {
477
     * // TODO:
478
     * // Si el provider devuelbe null habria que ver de construir aqui
479
     * // los metadatos basicos, como el Envelope y el SRS.
480
     *
481
     * // TODO: Estando en edicion el Envelope deberia de
482
     * // actualizarse usando el spatialManager
483
     * return this.provider.getMetadata();
484
     * }
485
     */
486

    
487
    @Override
488
    public Envelope getEnvelope() throws DataException {
489
        if (this.mode == MODE_FULLEDIT) {
490
                // Just in case another thread tries to write in the store
491
                synchronized (this) {
492
                        return this.spatialManager.getEnvelope();
493
                        }
494
        }
495
        if (hasDynValue(DataStore.METADATA_ENVELOPE)){
496
            return (Envelope)getDynValue(DataStore.METADATA_ENVELOPE);
497
        }
498
        Envelope envelope = this.provider.getEnvelope();
499
        if( envelope!=null ) {
500
            return envelope;
501
        }
502
        FeatureAttributeDescriptor attrdesc = this.getDefaultFeatureType().getDefaultGeometryAttribute();
503
        if( attrdesc == null || !attrdesc.isComputed() ) {
504
            return null;
505
        }
506
        final int index = attrdesc.getIndex();
507
        final MutableObject<Envelope> envelopeValue = new MutableObject<>();
508
        try {
509
            this.accept(new Visitor() {
510
                @Override
511
                public void visit(Object obj) throws VisitCanceledException, BaseException {
512
                    Feature f = (Feature) obj;
513
                    Geometry g =  (Geometry) f.get(index);
514
                    if( g == null ) {
515
                        return;
516
                    }
517
                    if( envelopeValue.getValue()==null ) {
518
                        envelopeValue.setValue(g.getEnvelope());
519
                    } else {
520
                        envelopeValue.getValue().add(g);
521
                    }
522
                }
523
            });
524
        } catch (Throwable th) {
525
            LOGGER.warn("Can't calculate envelope", th);
526
            return null;
527
        }
528
        return envelopeValue.getValue();
529
    }
530

    
531
    /**
532
     * @throws org.gvsig.fmap.dal.exception.DataException
533
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
534
     */
535
    @Override
536
    public IProjection getSRSDefaultGeometry() throws DataException {
537
        return this.getDefaultFeatureType().getDefaultSRS();
538
    }
539

    
540
    @Override
541
    public FeatureSelection createDefaultFeatureSelection()
542
        throws DataException {
543
        return new DefaultFeatureSelection(this);
544
    }
545

    
546
    @Override
547
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
548
        throws DataException {
549
        if (type.hasOID()) {
550
            return new DefaultFeatureProvider(type,
551
                this.provider.createNewOID());
552
        }
553
        return new DefaultFeatureProvider(type);
554
    }
555

    
556
    @Override
557
    public void saveToState(PersistentState state) throws PersistenceException {
558
        /*if (this.mode != FeatureStore.MODE_QUERY) {
559
            throw new PersistenceException(new IllegalStateException(
560
                this.getName()));
561
        }*/
562
        state.set("dataStoreName", this.getName());
563
        state.set("parameters", this.parameters);
564
        state.set("selection", this.selection);
565
        state.set("transforms", this.transforms);
566
        // TODO locks persistence
567
        // state.set("locks", this.locks);
568
        // TODO indexes persistence
569
        // state.set("indexes", this.indexes);
570
        Map evaluatedAttr = new HashMap(1);
571
        Iterator iterType = featureTypes.iterator();
572
        Iterator iterAttr;
573
        FeatureType type;
574
        DefaultFeatureAttributeDescriptor attr;
575
        List attrs;
576
        while (iterType.hasNext()) {
577
            type = (FeatureType) iterType.next();
578
            attrs = new ArrayList();
579
            iterAttr = type.iterator();
580
            while (iterAttr.hasNext()) {
581
                attr = (DefaultFeatureAttributeDescriptor) iterAttr.next();
582
                if ((attr.getEvaluator() != null)
583
                    && (attr.getEvaluator() instanceof Persistent)) {
584
                    attrs.add(attr);
585
                }
586
            }
587
            if (!attrs.isEmpty()) {
588
                evaluatedAttr.put(type.getId(), attrs);
589
            }
590

    
591
        }
592

    
593
        if (evaluatedAttr.isEmpty()) {
594
            evaluatedAttr = null;
595
        }
596

    
597
        state.set("evaluatedAttributes", evaluatedAttr);
598
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
599

    
600
    }
601

    
602
    @Override
603
    public void loadFromState(final PersistentState persistentState)
604
        throws PersistenceException {
605
        if (this.provider != null) {
606
            throw new PersistenceStoreAlreadyLoadedException(this.getName());
607
        }
608
        if (this.getManager() == null) {
609
            this.dataManager = (DefaultDataManager) DALLocator.getDataManager();
610
        }
611
        state.clear();
612
        try {
613
            state.put("parameters", persistentState.get("parameters"));
614
        } catch(Throwable th) {
615
            state.setBreakingsCause(th);
616
        }
617
        try {
618
            state.put("selection", persistentState.get("selection"));
619
        } catch(Throwable th) {
620
            state.setBreakingsCause(th);
621
        }
622
        try {
623
            state.put("transforms",  persistentState.get("transforms"));
624
        } catch(Throwable th) {
625
            state.setBreakingsCause(th);
626
        }
627
        try {
628
            state.put("evaluatedAttributes",  persistentState.get("evaluatedAttributes"));
629
        } catch(Throwable th) {
630
            state.setBreakingsCause(th);
631
        }
632
        try {
633
            state.put("defaultFeatureTypeId", persistentState.getString("defaultFeatureTypeId"));
634
        } catch(Throwable th) {
635
            state.setBreakingsCause(th);
636
        }
637
        load(state);
638
    }
639

    
640
    private void load(StateInformation state) {
641
        this.featureTypes = new ArrayList();
642
        this.defaultFeatureType = null;
643
        this.featureCount = null;
644

    
645
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
646
        try {
647
            intialize(dataManager, params);
648
        } catch(Throwable th) {
649
            state.setBreakingsCause(th);
650
        }
651

    
652
        try {
653
            DataStoreProvider prov = dataManager.createProvider(
654
                getStoreProviderServices(),
655
                params
656
            );
657
            setProvider(prov);
658
        } catch(Throwable th) {
659
            LOGGER.warn("Can't load store from state.", th);
660
            state.setBreakingsCause(th);
661
        }
662
        try {
663
            selection = (FeatureSelection) state.get("selection");
664
        } catch(Throwable th) {
665
            state.setBreakingsCause(th);
666
        }
667

    
668
        try {
669
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
670
            this.transforms.setFeatureStore(this);
671
            for( FeatureStoreTransform transform : this.transforms ) {
672
                try {
673
                    transform.setUp();
674
                } catch(Throwable th) {
675
                    state.setBreakingsCause(th);
676
                }
677
            }
678
        } catch(Throwable th) {
679
            state.setBreakingsCause(th);
680
        }
681

    
682
        try {
683
            Map evaluatedAttributes = (Map) state.get("evaluatedAttributes");
684
            if ((evaluatedAttributes != null) && !evaluatedAttributes.isEmpty()) {
685
                    Iterator iterEntries = evaluatedAttributes.entrySet().iterator();
686
                    while (iterEntries.hasNext()) {
687
                            Entry entry = (Entry) iterEntries.next();
688
                            List attrs = (List) entry.getValue();
689
                            if (attrs.isEmpty()) {
690
                                    continue;
691
                            }
692
                            int fTypePos = -1;
693
                            DefaultFeatureType type = null;
694
                            for (int i = 0; i < featureTypes.size(); i++) {
695
                                    type = (DefaultFeatureType) featureTypes.get(i);
696
                                    if (type.getId().equals(entry.getKey())) {
697
                                            fTypePos = i;
698
                                            break;
699
                                    }
700
                            }
701
                            if (type == null) {
702
                                    throw new PersistenceCantFindFeatureTypeException(
703
                                            getName(), (String) entry.getKey());
704
                            }
705
                            DefaultEditableFeatureType eType = (DefaultEditableFeatureType) type.getEditable();
706
                            Iterator<FeatureAttributeDescriptor> iterAttr = attrs.iterator();
707
                            while (iterAttr.hasNext()) {
708
                                    FeatureAttributeDescriptor attr = iterAttr.next();
709
                                    eType.addLike(attr);
710
                            }
711
                            featureTypes.set(fTypePos, eType.getNotEditableCopy());
712

    
713
                    }
714

    
715
            }
716
        } catch(Throwable th) {
717
            state.setBreakingsCause(th);
718
        }
719

    
720

    
721
        try {
722
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
723
            FeatureType ftype;
724

    
725
            if (defaultFeatureType == null ||
726
                    defaultFeatureType.getId() == null ||
727
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
728

    
729
                    ftype = getFeatureType(defaultFeatureTypeId);
730
                    if (ftype == null) {
731
                            /*
732
                             * Un error en el m?todo de PostgreSQL getName(), hace que
733
                             * el nombre del featureType sea valor retornado por el getProviderName()
734
                             * De momento se pone este parche para apa?arlo y poder mantener compatibilidad
735
                             * con proyectos antiguos (2.1 y 2.2)
736
                             */
737
                            ftype = getFeatureType(getName());
738
                            if(ftype == null ) {
739
                                    throw new RuntimeException("Can't locate feature type");
740
                            }
741
                    }
742
                    defaultFeatureType = ftype;
743
            }
744
        } catch(Throwable th) {
745
            state.setBreakingsCause(th);
746
        }
747

    
748
        LOGGER.info("load() broken:{}, {}, {}.",
749
                new Object[] { state.isBroken(), this.getProviderName(), params }
750
        );
751
    }
752

    
753
    public DataStoreProviderServices getStoreProviderServices() {
754
        return this;
755
    }
756

    
757
    public static void registerPersistenceDefinition() {
758
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
759
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
760
            DynStruct definition =
761
                manager.addDefinition(DefaultFeatureStore.class,
762
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
763
                        + " Persistent definition", null, null);
764
            definition.addDynFieldString("dataStoreName").setMandatory(true)
765
                .setPersistent(true);
766

    
767
            definition.addDynFieldObject("parameters")
768
                .setClassOfValue(DynObject.class).setMandatory(true)
769
                .setPersistent(true);
770

    
771
            definition.addDynFieldObject("selection")
772
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
773
                .setPersistent(true);
774

    
775
            definition.addDynFieldObject("transforms")
776
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
777
                .setMandatory(true).setPersistent(true);
778

    
779
            definition.addDynFieldMap("evaluatedAttributes")
780
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
781
                .setMandatory(false).setPersistent(true);
782

    
783
            definition.addDynFieldString("defaultFeatureTypeId")
784
                .setMandatory(true).setPersistent(true);
785
        }
786
    }
787

    
788
    public static void registerMetadataDefinition() throws MetadataException {
789
        MetadataManager manager = MetadataLocator.getMetadataManager();
790
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
791
            DynStruct metadataDefinition =
792
                manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
793
            metadataDefinition.extend(manager
794
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
795
        }
796
    }
797

    
798
    //
799
    // ====================================================================
800
    // Gestion de la seleccion
801
    //
802

    
803
    @Override
804
    public void setSelection(DataSet selection) throws DataException {
805
        this.setSelection((FeatureSet) selection);
806
    }
807

    
808
    @Override
809
    public DataSet createSelection() throws DataException {
810
        return createFeatureSelection();
811
    }
812

    
813
    @Override
814
    public DataSet getSelection() throws DataException {
815
        return this.getFeatureSelection();
816
    }
817

    
818
    @Override
819
    public void setSelection(FeatureSet selection) throws DataException {
820
        setSelection(selection, true);
821
    }
822

    
823
    public void setSelection(FeatureSet selection, boolean undoable)
824
        throws DataException {
825
        if (selection == null) {
826
            if (undoable) {
827
                throw new SelectionNotAllowedException(getName());
828
            }
829

    
830
        } else {
831
            if (selection.equals(this.selection)) {
832
                return;
833
            }
834
            if (!selection.isFromStore(this)) {
835
                throw new SelectionNotAllowedException(getName());
836
            }
837
        }
838

    
839
        if (this.selection != null) {
840
            this.selection.deleteObserver(this);
841
        }
842
        if (selection == null) {
843
            if (this.selection != null) {
844
                this.selection.dispose();
845
            }
846
            this.selection = null;
847
            return;
848
        }
849
        if (selection instanceof FeatureSelection) {
850
            if (undoable && isEditing()) {
851
                commands.selectionSet(this, this.selection,
852
                    (FeatureSelection) selection);
853
            }
854
            if (this.selection != null) {
855
                this.selection.dispose();
856
            }
857
            this.selection = (FeatureSelection) selection;
858
        } else {
859
            if (undoable && isEditing()) {
860
                commands.startComplex("_selectionSet");
861
            }
862
            if (selection instanceof DefaultFeatureSelection) {
863
                DefaultFeatureSelection defSelection =
864
                    (DefaultFeatureSelection) selection;
865
                defSelection.deselectAll(undoable);
866
                defSelection.select(selection, undoable);
867
            } else {
868
                this.selection.deselectAll();
869
                this.selection.select(selection);
870
            }
871
            if (undoable && isEditing()) {
872
                commands.endComplex();
873
            }
874
        }
875
        this.selection.addObserver(this);
876

    
877
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
878
    }
879

    
880
    @Override
881
    public FeatureSelection createFeatureSelection() throws DataException {
882
        return this.provider.createFeatureSelection();
883
    }
884

    
885
    @Override
886
    public FeatureSelection getFeatureSelection() throws DataException {
887
        if (selection == null) {
888
            this.selection = createFeatureSelection();
889
            this.selection.addObserver(this);
890
        }
891
        return selection;
892
    }
893

    
894
    //
895
    // ====================================================================
896
    // Gestion de notificaciones
897
    //
898

    
899
    @Override
900
    public void notifyChange(FeatureStoreNotification storeNotification) {
901
        try {
902
            delegateObservable.notifyObservers(storeNotification);
903
        } catch (Throwable ex) {
904
            LOGGER.warn("Problems notifying changes in the store '"+this.getName()+" ("+storeNotification.getType()+").",ex);
905
        }
906
    }
907

    
908
    @Override
909
    public void notifyChange(String notification) {
910
        if (delegateObservable != null) {
911
            notifyChange(new DefaultFeatureStoreNotification(this, notification));
912
        }
913

    
914
    }
915

    
916
    @Override
917
    public void notifyChange(String notification, FeatureProvider data) {
918
        Feature f = null;
919
        try {
920
            f = createFeature(data);
921
        } catch (Throwable ex) {
922
            LOGGER.warn("Problems creating a feature to notifying changes in the store '"+this.getName()+" ("+notification+").",ex);
923
        }
924
        notifyChange(notification, f);
925
    }
926

    
927
    public void notifyChange(String notification, Feature feature) {
928
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
929
            feature));
930
    }
931

    
932
    public void notifyChange(String notification, Command command) {
933
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
934
            command));
935
    }
936

    
937
    public void notifyChange(String notification, EditableFeatureType type) {
938
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
939
            type));
940
    }
941

    
942
    @Override
943
    public void notifyChange(String notification, Resource resource) {
944
        notifyChange(new DefaultFeatureStoreNotification(this,
945
            DataStoreNotification.RESOURCE_CHANGED));
946
    }
947

    
948
    //
949
    // ====================================================================
950
    // Gestion de bloqueos
951
    //
952

    
953
    @Override
954
    public boolean isLocksSupported() {
955
        return this.provider.isLocksSupported();
956
    }
957

    
958
    @Override
959
    public FeatureLocks getLocks() throws DataException {
960
        if (!this.provider.isLocksSupported()) {
961
            LOGGER.warn("Locks not supported");
962
            return null;
963
        }
964
        if (locks == null) {
965
            this.locks = this.provider.createFeatureLocks();
966
        }
967
        return locks;
968
    }
969

    
970
    //
971
    // ====================================================================
972
    // Interface Observable
973
    //
974

    
975
    @Override
976
    public void disableNotifications() {
977
        this.delegateObservable.disableNotifications();
978

    
979
    }
980

    
981
    @Override
982
    public void enableNotifications() {
983
        this.delegateObservable.enableNotifications();
984
    }
985

    
986
    @Override
987
    public void beginComplexNotification() {
988
        this.delegateObservable.beginComplexNotification();
989

    
990
    }
991

    
992
    @Override
993
    public void endComplexNotification() {
994
        this.delegateObservable.endComplexNotification();
995

    
996
    }
997

    
998
    @Override
999
    public void addObserver(Observer observer) {
1000
        if (delegateObservable != null) {
1001
            this.delegateObservable.addObserver(observer);
1002
        }
1003
    }
1004

    
1005
    @Override
1006
    public void deleteObserver(Observer observer) {
1007
        if (delegateObservable != null) {
1008
            this.delegateObservable.deleteObserver(observer);
1009
        }
1010
    }
1011

    
1012
    @Override
1013
    public void deleteObservers() {
1014
        this.delegateObservable.deleteObservers();
1015

    
1016
    }
1017

    
1018
    //
1019
    // ====================================================================
1020
    // Interface Observer
1021
    //
1022
    // Usado para observar:
1023
    // - su seleccion
1024
    // - sus bloqueos
1025
    // - sus recursos
1026
    //
1027

    
1028
    @Override
1029
    public void update(Observable observable, Object notification) {
1030
        if (observable instanceof FeatureSet) {
1031
            if (observable == this.selection) {
1032
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1033
            } else if (observable == this.locks) {
1034
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1035
            }
1036

    
1037
        } else if (observable instanceof FeatureStoreProvider) {
1038
            if (observable == this.provider) {
1039

    
1040
            }
1041
        } else if (observable instanceof FeatureReferenceSelection) {
1042
            if(notification instanceof String){
1043
                    this.notifyChange((String)notification);
1044
            }
1045
        }
1046
    }
1047

    
1048
    //
1049
    // ====================================================================
1050
    // Edicion
1051
    //
1052

    
1053
    private void newVersionOfUpdate() {
1054
        this.versionOfUpdate++;
1055
    }
1056

    
1057
    private long currentVersionOfUpdate() {
1058
        return this.versionOfUpdate;
1059
    }
1060

    
1061
    private void checkInEditingMode() throws NeedEditingModeException {
1062
        if (mode != MODE_FULLEDIT) {
1063
            throw new NeedEditingModeException(this.getName());
1064
        }
1065
    }
1066

    
1067
    private void checkNotInAppendMode() throws IllegalStateException {
1068
        if (mode == MODE_APPEND) {
1069
                        throw new IllegalStateException("Error: store "
1070
                                        + this.getFullName() + " is in append mode");
1071
        }
1072
    }
1073

    
1074
    private void checkIsOwnFeature(Feature feature)
1075
        throws IllegalFeatureException {
1076
        if (((DefaultFeature) feature).getStore() != this) {
1077
            throw new IllegalFeatureException(this.getName());
1078
        }
1079
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1080
        // fixFeatureType((DefaultFeatureType) feature.getType());
1081
    }
1082

    
1083
    private void exitEditingMode() {
1084
        if (commands != null) {
1085
            commands.clear();
1086
            commands = null;
1087
        }
1088

    
1089
        if (featureTypeManager != null) {
1090
            featureTypeManager.dispose();
1091
            featureTypeManager = null;
1092

    
1093
        }
1094

    
1095
        // TODO implementar un dispose para estos dos
1096
        featureManager = null;
1097
        spatialManager = null;
1098

    
1099
        featureCount = null;
1100

    
1101
        mode = MODE_QUERY;
1102
        hasStrongChanges = true; // Lo deja a true por si las moscas
1103
        hasInserts = true;
1104
    }
1105

    
1106
    @Override
1107
    synchronized public void edit() throws DataException {
1108
        edit(MODE_FULLEDIT);
1109
    }
1110

    
1111
    @Override
1112
    synchronized public void edit(int mode) throws DataException {
1113
        LOGGER.debug("Starting editing in mode: {}", mode);
1114
        try {
1115
            if (this.mode != MODE_QUERY) {
1116
                throw new AlreadyEditingException(this.getName());
1117
            }
1118
            if (!this.provider.supportsAppendMode()) {
1119
                mode = MODE_FULLEDIT;
1120
            }
1121
            switch (mode) {
1122
            case MODE_QUERY:
1123
                throw new IllegalStateException(this.getName());
1124

    
1125
            case MODE_FULLEDIT:
1126
                if (!this.transforms.isEmpty()) {
1127
                    throw new IllegalStateException(this.getName());
1128
                }
1129
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
1130
                invalidateIndexes();
1131
                featureManager = new FeatureManager();
1132
                featureTypeManager = new FeatureTypeManager(this);
1133
                spatialManager = new SpatialManager(this, provider.getEnvelope());
1134

    
1135
                commands = new DefaultFeatureCommandsStack(
1136
                        this, featureManager,
1137
                        spatialManager, featureTypeManager);
1138
                this.mode = MODE_FULLEDIT;
1139
                hasStrongChanges = false;
1140
                hasInserts = false;
1141
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1142
                break;
1143
            case MODE_APPEND:
1144
                if (!this.transforms.isEmpty()) {
1145
                    throw new IllegalStateException(this.getName());
1146
                }
1147
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
1148
                invalidateIndexes();
1149
                this.provider.beginAppend();
1150
                this.mode = MODE_APPEND;
1151
                hasInserts = false;
1152
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1153
                break;
1154
            }
1155
        } catch (Exception e) {
1156
            throw new StoreEditException(e, this.getName());
1157
        }
1158
    }
1159

    
1160
    private void invalidateIndexes() {
1161
        setIndexesValidStatus(false);
1162
    }
1163

    
1164
    private void setIndexesValidStatus(boolean valid) {
1165
        FeatureIndexes theIndexes = getIndexes();
1166
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1167
            ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1168
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1169
            FeatureIndex index = (FeatureIndex) iterator.next();
1170
            if (index instanceof FeatureIndexProviderServices) {
1171
                FeatureIndexProviderServices indexServices =
1172
                    (FeatureIndexProviderServices) index;
1173
                indexServices.setValid(valid);
1174
            }
1175
        }
1176
    }
1177

    
1178
    private void updateIndexes() throws FeatureIndexException {
1179
        FeatureIndexes theIndexes = getIndexes();
1180
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1181
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1182
            FeatureIndex index = (FeatureIndex) iterator.next();
1183
            if (index instanceof FeatureIndexProviderServices) {
1184
                FeatureIndexProviderServices indexServices =
1185
                    (FeatureIndexProviderServices) index;
1186
                indexServices.fill(true, null);
1187
            }
1188
        }
1189
    }
1190

    
1191
    private void waitForIndexes() {
1192
        FeatureIndexes theIndexes = getIndexes();
1193
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1194
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1195
            FeatureIndex index = (FeatureIndex) iterator.next();
1196
            if (index instanceof FeatureIndexProviderServices) {
1197
                FeatureIndexProviderServices indexServices =
1198
                    (FeatureIndexProviderServices) index;
1199
                indexServices.waitForIndex();
1200
            }
1201
        }
1202
    }
1203

    
1204
    private void disposeIndexes() {
1205
        FeatureIndexes theIndexes = getIndexes();
1206
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1207
        if( theIndexes==null ) {
1208
            return;
1209
        }
1210
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1211
            FeatureIndex index = (FeatureIndex) iterator.next();
1212
            if (index instanceof FeatureIndexProviderServices) {
1213
                FeatureIndexProviderServices indexServices =
1214
                    (FeatureIndexProviderServices) index;
1215
                indexServices.dispose();
1216
            }
1217
        }
1218
    }
1219

    
1220
    @Override
1221
    public boolean isEditing() {
1222
        return mode == MODE_FULLEDIT;
1223
    }
1224

    
1225
    @Override
1226
    public boolean isAppending() {
1227
        return mode == MODE_APPEND;
1228
    }
1229

    
1230
    @Override
1231
    synchronized public void update(EditableFeatureType type)
1232
        throws DataException {
1233
        try {
1234
            if (type == null) {
1235
                throw new NullFeatureTypeException(getName());
1236
            }
1237
            if (mode == MODE_QUERY && type.hasOnlyMetadataChanges(this.featureTypeManager.getOriginalFeatureType())) {
1238
                FeatureType theType = type.getCopy();
1239
                if( defaultFeatureType.getId().equals(theType.getId()) ) {
1240
                    defaultFeatureType = theType;
1241
                }
1242
                for (int i = 0; i < featureTypes.size(); i++) {
1243
                    FeatureType featureType = featureTypes.get(i);
1244
                    if( featureType.getId().equals(theType.getId()) ) {
1245
                        featureTypes.set(i, theType);
1246
                        break;
1247
                    }
1248
                }
1249
                saveDALFile();
1250
                return ;
1251
            }
1252
            boolean typehasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1253
            if (typehasStrongChanges) {
1254
                checkInEditingMode();
1255
            }  else if(this.isAppending()) {
1256
                throw new NeedEditingModeException(this.getName());
1257
            }
1258
            // FIXME: Comprobar que es un featureType aceptable.
1259
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
1260
            newVersionOfUpdate();
1261
            
1262
            FeatureType oldt = type.getSource().getCopy();
1263
            FeatureType newt = type.getCopy();
1264
            commands.update(newt, oldt);
1265
            if (typehasStrongChanges) { 
1266
                hasStrongChanges = true;
1267
            }
1268
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1269
        } catch (Exception e) {
1270
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1271
        }
1272
    }
1273

    
1274
    @Override
1275
    public void delete(Feature feature) throws DataException {
1276
        this.commands.delete(feature);
1277
    }
1278

    
1279
    synchronized public void doDelete(Feature feature) throws DataException {
1280
        try {
1281
            checkInEditingMode();
1282
            checkIsOwnFeature(feature);
1283
            if (feature instanceof EditableFeature) {
1284
                throw new StoreDeleteEditableFeatureException(getName());
1285
            }
1286
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1287

    
1288
            //Update the featureManager and the spatialManager
1289
            featureManager.delete(feature.getReference());
1290
            spatialManager.deleteFeature(feature);
1291

    
1292
            newVersionOfUpdate();
1293
            hasStrongChanges = true;
1294
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1295
        } catch (Exception e) {
1296
            throw new StoreDeleteFeatureException(e, this.getName());
1297
        }
1298
    }
1299

    
1300
    private static EditableFeature lastChangedFeature = null;
1301

    
1302
    @Override
1303
    public synchronized void insert(EditableFeature feature)
1304
        throws DataException {
1305
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1306
        try {
1307
            switch (mode) {
1308
            case MODE_QUERY:
1309
                throw new NeedEditingModeException(this.getName());
1310

    
1311
            case MODE_APPEND:
1312
                checkIsOwnFeature(feature);
1313
                if (feature.getSource() != null) {
1314
                    throw new NoNewFeatureInsertException(this.getName());
1315
                }
1316
                this.featureCount = null;
1317
                notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1318
                feature.validate(Feature.UPDATE);
1319
                provider.append(((DefaultEditableFeature) feature).getData());
1320
                hasStrongChanges = true;
1321
                hasInserts = true;
1322
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1323
                break;
1324

    
1325
            case MODE_FULLEDIT:
1326
                if (feature.getSource() != null) {
1327
                    throw new NoNewFeatureInsertException(this.getName());
1328
                }
1329
                commands.insert(feature);
1330
            }
1331
        } catch (Exception e) {
1332
            throw new StoreInsertFeatureException(e, this.getName());
1333
        }
1334
    }
1335

    
1336
    synchronized public void doInsert(EditableFeature feature)
1337
        throws DataException {
1338
        checkIsOwnFeature(feature);
1339

    
1340
        waitForIndexes();
1341

    
1342
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1343
        newVersionOfUpdate();
1344
        if ((lastChangedFeature == null)
1345
            || (lastChangedFeature.getSource() != feature.getSource())) {
1346
            lastChangedFeature = feature;
1347
            feature.validate(Feature.UPDATE);
1348
            lastChangedFeature = null;
1349
        }
1350
        //Update the featureManager and the spatialManager
1351
        ((DefaultEditableFeature) feature).setInserted(true);
1352
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1353

    
1354

    
1355
        featureManager.add(newFeature);
1356
        spatialManager.insertFeature(newFeature);
1357

    
1358
        hasStrongChanges = true;
1359
        hasInserts = true;
1360
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1361
    }
1362

    
1363
    @Override
1364
    public void update(EditableFeature feature)
1365
    throws DataException {
1366
        if ((feature).getSource() == null) {
1367
            insert(feature);
1368
            return;
1369
        }
1370
        commands.update(feature, feature.getSource());
1371
    }
1372

    
1373
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1374
        throws DataException {
1375
        try {
1376
            checkInEditingMode();
1377
            checkIsOwnFeature(feature);
1378
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature);
1379
            newVersionOfUpdate();
1380
            if ((lastChangedFeature == null)
1381
                || (lastChangedFeature.getSource() != feature.getSource())) {
1382
                lastChangedFeature = feature;
1383
                feature.validate(Feature.UPDATE);
1384
                lastChangedFeature = null;
1385
            }
1386

    
1387
            //Update the featureManager and the spatialManager
1388
            Feature newf = feature.getNotEditableCopy();
1389
            featureManager.update(newf, oldFeature);
1390
            spatialManager.updateFeature(newf, oldFeature);
1391

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

    
1399
    @Override
1400
    synchronized public void redo() throws RedoException {
1401
        Command redo = commands.getNextRedoCommand();
1402
        try {
1403
            checkInEditingMode();
1404
        } catch (NeedEditingModeException ex) {
1405
            throw new RedoException(redo, ex);
1406
        }
1407
        notifyChange(FeatureStoreNotification.BEFORE_REDO, redo);
1408
        newVersionOfUpdate();
1409
        commands.redo();
1410
        hasStrongChanges = true;
1411
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1412
    }
1413

    
1414
    @Override
1415
    synchronized public void undo() throws UndoException {
1416
        Command undo = commands.getNextUndoCommand();
1417
        try {
1418
            checkInEditingMode();
1419
        } catch (NeedEditingModeException ex) {
1420
            throw new UndoException(undo, ex);
1421
        }
1422
        notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo);
1423
        newVersionOfUpdate();
1424
        commands.undo();
1425
        hasStrongChanges = true;
1426
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1427
    }
1428

    
1429
    @Override
1430
    public List getRedoInfos() {
1431
        if (isEditing() && (commands != null)) {
1432
            return commands.getRedoInfos();
1433
        } else {
1434
            return null;
1435
        }
1436
    }
1437

    
1438
    @Override
1439
    public List getUndoInfos() {
1440
        if (isEditing() && (commands != null)) {
1441
            return commands.getUndoInfos();
1442
        } else {
1443
            return null;
1444
        }
1445
    }
1446

    
1447
    public synchronized FeatureCommandsStack getCommandsStack()
1448
        throws DataException {
1449
        checkInEditingMode();
1450
        return commands;
1451
    }
1452

    
1453
    @Override
1454
    synchronized public void cancelEditing() throws DataException {
1455
        if( spatialManager!=null ) {
1456
            spatialManager.cancelModifies();
1457
        }
1458
        try {
1459
            switch (mode) {
1460
            case MODE_QUERY:
1461
                throw new NeedEditingModeException(this.getName());
1462

    
1463
            case MODE_APPEND:
1464
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1465
                provider.abortAppend();
1466
                exitEditingMode();
1467
                ((FeatureSelection) this.getSelection()).deselectAll();
1468
                updateIndexes();
1469
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1470

    
1471
            case MODE_FULLEDIT:
1472
                boolean clearSelection = this.hasStrongChanges;
1473
                if (this.selection instanceof FeatureReferenceSelection) {
1474
                    clearSelection = this.hasInserts;
1475
                }
1476
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1477
                exitEditingMode();
1478
                if (clearSelection) {
1479
                    ((FeatureSelection) this.getSelection()).deselectAll();
1480
                }
1481
                updateIndexes();
1482
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1483
            }
1484
        } catch (Exception e) {
1485
            throw new StoreCancelEditingException(e, this.getName());
1486
        }
1487
    }
1488

    
1489
    @Override
1490
    synchronized public void finishEditing() throws DataException {
1491
        LOGGER.debug("finish editing of mode: {}", mode);
1492
        try {
1493

    
1494
            /*
1495
             * Selection needs to be cleared when editing stops
1496
             * to prevent conflicts with selection remaining from
1497
             * editing mode.
1498
             */
1499
//            ((FeatureSelection) this.getSelection()).deselectAll();
1500
            Map<String,List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1501
            switch (mode) {
1502
            case MODE_QUERY:
1503
                throw new NeedEditingModeException(this.getName());
1504

    
1505
            case MODE_APPEND:
1506
                if( selection!=null ) {
1507
                    selection = null;
1508
                }
1509
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1510
                saveDALFile();
1511
                provider.endAppend();
1512
                exitEditingMode();
1513
                this.updateComputedFields(computedFields);
1514
                loadDALFile();
1515
                updateIndexes();
1516
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1517
                break;
1518

    
1519
            case MODE_FULLEDIT:
1520
                if (hasStrongChanges && !this.allowWrite()) {
1521
                    throw new WriteNotAllowedException(getName());
1522
                }
1523
                saveDALFile();
1524
                if(featureManager.isSelectionCompromised() && selection!=null ) {
1525
                    selection = null;
1526
                }
1527
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1528
                if (hasStrongChanges) {
1529
                    validateFeatures(Feature.FINISH_EDITING);
1530

    
1531
                    /*
1532
                     * This will throw a PerformEditingExceptionif the provider
1533
                     * does not accept the changes (for example, an invalid field name)
1534
                     */
1535
                    provider.performChanges(featureManager.getDeleted(),
1536
                        featureManager.getInserted(),
1537
                        featureManager.getUpdated(),
1538
                        removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1539
                    
1540
                }  
1541
                this.updateComputedFields(computedFields);
1542
                exitEditingMode();
1543
                loadDALFile();
1544
                updateIndexes();
1545
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1546
                break;
1547
            }
1548
        } catch (PerformEditingException pee) {
1549
            throw new WriteException(provider.getSourceId().toString(), pee);
1550
        } catch (Exception e) {
1551
            throw new FinishEditingException(e);
1552
        }
1553
    }
1554
    private Map<String,List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
1555
        Map<String,List<FeatureAttributeDescriptor>> r = new HashMap<>();
1556
        
1557
        List<FeatureType> theTypes = new ArrayList<>();
1558
        theTypes.addAll(this.getFeatureTypes());
1559
        theTypes.add(this.getDefaultFeatureType());
1560
        for( int n=0; n<theTypes.size(); n++ ) {
1561
            FeatureType type = theTypes.get(n);
1562
                for (FeatureAttributeDescriptor attrdesc : type) {
1563
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
1564
                    if( emulator!= null) {
1565
                        List<FeatureAttributeDescriptor> l = r.get(type.getId());
1566
                        if (l==null) {
1567
                            l = new ArrayList<>();
1568
                            r.put(type.getId(), l);
1569
                        }
1570
                        l.add(attrdesc);
1571
                    }
1572
            }
1573
        }
1574
        return r;
1575
    }
1576
    private void updateComputedFields(Map<String,List<FeatureAttributeDescriptor>> computedFields) throws DataException {
1577

    
1578
        List<FeatureType> theTypes = new ArrayList<>();
1579
        theTypes.addAll(this.getFeatureTypes());
1580
        theTypes.add(this.getDefaultFeatureType());
1581
        for( int n=0; n<theTypes.size(); n++ ) {
1582
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1583
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1584
            if(x!=null && !x.isEmpty()) {
1585
                for (FeatureAttributeDescriptor attrdesc : x) {
1586
                    if (type.get(attrdesc.getName())==null) {
1587
                        type.add(attrdesc);
1588
                    }
1589
                }
1590
            }
1591
        }
1592
        
1593
    }
1594
    private List<FeatureStoreProvider.FeatureTypeChanged> removeCalculatedAttributes(List<FeatureStoreProvider.FeatureTypeChanged> ftypes) {
1595
        // FIXME: Falta por implementar
1596
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
1597
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
1598
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
1599
//                if (attributeDescriptor.isComputed()) {
1600
//                    target.remove(attributeDescriptor.getName());
1601
//                }
1602
//            }
1603
//        }
1604
        return ftypes;
1605
    }
1606
    
1607

    
1608
    private void saveDALFile() {       
1609
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1610
        try {
1611
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1612
            if( resourcesStorage == null || resourcesStorage.isReadOnly() ) {
1613
                return;
1614
            }
1615
            resource = resourcesStorage.getResource("dal");
1616
            if( resource == null || resource.isReadOnly() ) {
1617
                return;
1618
            }
1619
            DALFile dalFile = DALFile.getDALFile();
1620
            dalFile.setStore(this);
1621
            if( !dalFile.isEmpty() ) {
1622
                dalFile.write(resource);
1623
            }
1624
        } catch (Throwable ex) {
1625
            LOGGER.warn("Can't save DAL resource", ex);
1626
        } finally {
1627
            IOUtils.closeQuietly(resource);
1628
        }
1629
    }
1630
    
1631
    private void loadDALFile() {
1632
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1633
        try {
1634
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1635
            if( resourcesStorage == null ) {
1636
                return;
1637
            }
1638
            resource = resourcesStorage.getResource("dal");
1639
            if( resource == null || !resource.exists() ) {
1640
                return;
1641
            }
1642
            DALFile dalFile = DALFile.getDALFile(resource);
1643
            if( !dalFile.isEmpty() ) {
1644
                dalFile.updateStore(this);
1645
            }
1646
        } catch (Throwable ex) {
1647
            LOGGER.warn("Can't load DAL resource", ex);
1648
        } finally {
1649
            IOUtils.closeQuietly(resource);
1650
        }
1651
    }
1652
    
1653
    /**
1654
     * Save changes in the provider without leaving the edit mode.
1655
     * Do not call observers to communicate a change of ediding mode.
1656
     * The operation's history is eliminated to prevent inconsistencies
1657
     * in the data.
1658
     *
1659
     * @throws DataException
1660
     */
1661
    @Override
1662
    synchronized public void commitChanges() throws DataException {
1663
      LOGGER.debug("commitChanges of mode: {}", mode);
1664
      if( !canCommitChanges() ) {
1665
              throw new WriteNotAllowedException(getName());
1666
      }
1667
      try {
1668
        switch (mode) {
1669
        case MODE_QUERY:
1670
          throw new NeedEditingModeException(this.getName());
1671

    
1672
        case MODE_APPEND:
1673
          this.provider.endAppend();
1674
          exitEditingMode();
1675
          invalidateIndexes();
1676
          this.provider.beginAppend();
1677
          hasInserts = false;
1678
          break;
1679

    
1680
        case MODE_FULLEDIT:
1681
          if (hasStrongChanges && !this.allowWrite()) {
1682
            throw new WriteNotAllowedException(getName());
1683
          }
1684
          if (hasStrongChanges) {
1685
            validateFeatures(Feature.FINISH_EDITING);
1686
            provider.performChanges(featureManager.getDeleted(),
1687
              featureManager.getInserted(),
1688
              featureManager.getUpdated(),
1689
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1690
          }
1691
          invalidateIndexes();
1692
          featureManager = new FeatureManager();
1693
          featureTypeManager = new FeatureTypeManager(this);
1694
          spatialManager = new SpatialManager(this, provider.getEnvelope());
1695

    
1696
          commands =
1697
            new DefaultFeatureCommandsStack(this, featureManager,
1698
              spatialManager, featureTypeManager);
1699
          featureCount = null;
1700
          hasStrongChanges = false;
1701
          hasInserts = false;
1702
          break;
1703
        }
1704
      } catch (Exception e) {
1705
        throw new FinishEditingException(e);
1706
      }
1707
    }
1708

    
1709
    @Override
1710
    synchronized public boolean canCommitChanges() throws DataException {
1711
        if ( !this.allowWrite()) {
1712
                return false;
1713
        }
1714
            switch (mode) {
1715
            default:
1716
        case MODE_QUERY:
1717
                return false;
1718

    
1719
        case MODE_APPEND:
1720
                return true;
1721

    
1722
        case MODE_FULLEDIT:
1723
            List types = this.getFeatureTypes();
1724
            for( int i=0; i<types.size(); i++ ) {
1725
                    Object type = types.get(i);
1726
                    if( type instanceof DefaultEditableFeatureType ) {
1727
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1728
                                    return false;
1729
                            }
1730
                    }
1731
            }
1732
            return true;
1733
            }
1734
    }
1735

    
1736
    @Override
1737
    public void beginEditingGroup(String description)
1738
        throws NeedEditingModeException {
1739
        checkInEditingMode();
1740
        commands.startComplex(description);
1741
    }
1742

    
1743
    @Override
1744
    public void endEditingGroup() throws NeedEditingModeException {
1745
        checkInEditingMode();
1746
        commands.endComplex();
1747
    }
1748

    
1749
    @Override
1750
    public boolean isAppendModeSupported() {
1751
        return this.provider.supportsAppendMode();
1752
    }
1753

    
1754
    @Override
1755
    public void export(DataServerExplorer explorer, String provider,
1756
        NewFeatureStoreParameters params) throws DataException {
1757

    
1758
        if (this.getFeatureTypes().size() != 1) {
1759
            throw new NotYetImplemented(
1760
                "export whith more than one type not yet implemented");
1761
        }
1762
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1763
        FeatureStore target = null;
1764
        FeatureSet features = null;
1765
        DisposableIterator iterator = null;
1766
        try {
1767
            FeatureType type = this.getDefaultFeatureType();
1768
            if ((params.getDefaultFeatureType() == null)
1769
                || (params.getDefaultFeatureType().size() == 0)) {
1770
                params.setDefaultFeatureType(type.getEditable());
1771

    
1772
            }
1773
            explorer.add(provider, params, true);
1774

    
1775
            DataManager manager = DALLocator.getDataManager();
1776
            target = (FeatureStore) manager.openStore(provider, params);
1777
            FeatureType targetType = target.getDefaultFeatureType();
1778

    
1779
            target.edit(MODE_APPEND);
1780
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
1781
            if (featureSelection.getSize() > 0) {
1782
                features = this.getFeatureSelection();
1783
            } else {
1784
                if ((pkattrs != null) && (pkattrs.length > 0)) {
1785
                    FeatureQuery query = createFeatureQuery();
1786
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
1787
                        query.getOrder().add(pkattr.getName(), true);
1788
                    }
1789
                    features = this.getFeatureSet(query);
1790
                } else {
1791
                    features = this.getFeatureSet();
1792
                }
1793
            }
1794
            iterator = features.fastIterator();
1795
            while (iterator.hasNext()) {
1796
                DefaultFeature feature = (DefaultFeature) iterator.next();
1797
                target.insert(target.createNewFeature(targetType, feature));
1798
            }
1799
            target.finishEditing();
1800
            target.dispose();
1801
        } catch (Exception e) {
1802
            throw new DataExportException(e, params.toString());
1803
        } finally {
1804
            dispose(iterator);
1805
            dispose(features);
1806
            dispose(target);
1807
        }
1808
    }
1809

    
1810
    public void copyTo(final FeatureStore target) {
1811
        boolean finishEditingAtEnd = false;
1812
        try {
1813
            if( !target.isEditing() && !target.isAppending() ) {
1814
                finishEditingAtEnd = true;
1815
                target.edit(MODE_APPEND);
1816
            }
1817
            this.accept(new Visitor() {
1818
                @Override
1819
                public void visit(Object obj) throws VisitCanceledException, BaseException {
1820
                    Feature f_src = (Feature) obj;
1821
                    EditableFeature f_dst = target.createNewFeature(f_src);
1822
                    target.insert(f_dst);
1823
                }
1824
            });
1825
            if( finishEditingAtEnd ) {
1826
                target.finishEditing();
1827
            }
1828
            
1829
        } catch(Exception ex) {
1830
            try {
1831
                if( finishEditingAtEnd ) {
1832
                    target.cancelEditing();
1833
                }
1834
            } catch (Exception ex1) {
1835
            }
1836
            throw new RuntimeException("Can't copy store.",ex);
1837
        }
1838
            
1839
    }
1840
    
1841
    //
1842
    // ====================================================================
1843
    // Obtencion de datos
1844
    // getDataCollection, getFeatureCollection
1845
    //
1846

    
1847
    @Override
1848
    public DataSet getDataSet() throws DataException {
1849
        checkNotInAppendMode();
1850
        FeatureQuery query =
1851
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1852
        return new DefaultFeatureSet(this, query);
1853
    }
1854

    
1855
    @Override
1856
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1857
        checkNotInAppendMode();
1858
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1859
    }
1860

    
1861
    @Override
1862
    public void getDataSet(Observer observer) throws DataException {
1863
        checkNotInAppendMode();
1864
        this.getFeatureSet(null, observer);
1865
    }
1866

    
1867
    @Override
1868
    public void getDataSet(DataQuery dataQuery, Observer observer)
1869
        throws DataException {
1870
        checkNotInAppendMode();
1871
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1872
    }
1873

    
1874
    @Override
1875
    public FeatureSet getFeatureSet() throws DataException {
1876
        return this.getFeatureSet((FeatureQuery)null);
1877
    }
1878

    
1879
    @Override
1880
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1881
        throws DataException {
1882
        checkNotInAppendMode();
1883
        if( featureQuery==null ) {
1884
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1885
        }
1886
        return new DefaultFeatureSet(this, featureQuery);
1887
    }
1888

    
1889
    @Override
1890
    public FeatureSet getFeatureSet(String filter) throws DataException {
1891
        return this.getFeatureSet(filter, null, true);
1892
    }
1893

    
1894
    @Override
1895
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
1896
        return this.getFeatureSet(filter, sortBy, true);
1897
    }
1898

    
1899
    @Override
1900
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
1901
        return this.getFeatureSet(filter, null, true);
1902
    }
1903
    
1904
    @Override
1905
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
1906
        return this.getFeatureSet(filter, sortBy, true);
1907
    }
1908

    
1909
    @Override
1910
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
1911
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1912
        return this.getFeatureSet(query);
1913
    }
1914
    
1915
    @Override
1916
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
1917
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1918
        return this.getFeatureSet(query);
1919
    }
1920
    
1921
    @Override
1922
    public List<Feature> getFeatures(String filter)  {
1923
        return this.getFeatures(filter, null, true);
1924
    }
1925

    
1926
    @Override
1927
    public List<Feature> getFeatures(String filter, String sortBy)  {
1928
        return this.getFeatures(filter, sortBy, true);
1929
    }
1930

    
1931
    @Override
1932
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
1933
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1934
        return this.getFeatures(query, 0);
1935
    }
1936
    
1937
    @Override
1938
    public List<Feature> getFeatures(Expression filter)  {
1939
        return this.getFeatures(filter, null, true);
1940
    }
1941

    
1942
    @Override
1943
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
1944
        return this.getFeatures(filter, sortBy, true);
1945
    }
1946

    
1947
    @Override
1948
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
1949
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1950
        return this.getFeatures(query, 0);
1951
    }
1952
    
1953
    @Override
1954
    public List<Feature> getFeatures(FeatureQuery query)  {
1955
        return this.getFeatures(query, 0);
1956
    }
1957
    
1958
    @Override
1959
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
1960
        try {
1961
            if( pageSize<=0 ) {
1962
                pageSize = 100;
1963
            }
1964
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
1965
            return pager.asList();
1966
        } catch (BaseException ex) {
1967
            throw new RuntimeException("Can't create the list of features.", ex);
1968
        }
1969
    }
1970

    
1971
    @Override
1972
    public List<Feature> getFeatures() {
1973
        return this.getFeatures(null, 0);
1974
    }
1975

    
1976
    @Override
1977
    public Feature first() throws DataException {
1978
        return this.findFirst((FeatureQuery)null);
1979
    }
1980
    
1981
    @Override
1982
    public Feature findFirst(String filter) throws DataException {
1983
        return this.findFirst(filter, null, true);
1984
    }
1985

    
1986
    @Override
1987
    public Feature findFirst(String filter, String sortBy) throws DataException {
1988
        return this.findFirst(filter, sortBy, true);
1989
    }
1990

    
1991
    @Override
1992
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
1993
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1994
        return findFirst(query);
1995
    }
1996
    
1997
    @Override
1998
    public Feature findFirst(Expression filter) throws DataException {
1999
        return this.findFirst(filter, null, true);
2000
    }
2001

    
2002
    @Override
2003
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2004
        return this.findFirst(filter, sortBy, true);
2005
    }
2006

    
2007
    @Override
2008
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2009
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2010
        return findFirst(query);
2011
    }
2012
    
2013
    @Override
2014
    public Feature findFirst(FeatureQuery query) throws DataException {
2015
        if( query == null ) {
2016
            query = this.createFeatureQuery();
2017
        } else {
2018
            query = query.getCopy();
2019
        }
2020
        query.setLimit(1);
2021
        final MutableObject<Feature> feature = new MutableObject<>();
2022
        try {
2023
            this.accept(new Visitor() {
2024
                @Override
2025
                public void visit(Object obj) throws VisitCanceledException, BaseException {
2026
                    feature.setValue((Feature) obj);
2027
                    throw new VisitCanceledException();
2028
                }
2029
            }, query);
2030
        } catch(VisitCanceledException ex) {
2031

    
2032
        } catch(DataException ex) {
2033
            throw ex;
2034
        } catch(Exception ex) {
2035
            throw new RuntimeException("", ex);
2036
        }
2037
        return feature.getValue();
2038
    }
2039

    
2040
    @Override
2041
    public void accept(Visitor visitor) throws BaseException {
2042
        this.accept(visitor, null);
2043
    }
2044

    
2045
    @Override
2046
    public void accept(Visitor visitor, DataQuery dataQuery)
2047
        throws BaseException {
2048
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2049
        try {
2050
            set.accept(visitor);
2051
        } finally {
2052
            set.dispose();
2053
        }
2054
    }
2055

    
2056
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2057
        throws DataException {
2058
        DefaultFeatureType fType =
2059
            (DefaultFeatureType) this.getFeatureType(featureQuery
2060
                .getFeatureTypeId());
2061
        if( featureQuery.hasAttributeNames() || 
2062
            featureQuery.hasConstantsAttributeNames() ||
2063
            fType.hasRequiredFields()    
2064
            ) {
2065
            if( featureQuery.isGrouped() ) {
2066
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2067
            } else {
2068
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2069
            }
2070
        }
2071
        return fType;
2072
    }
2073

    
2074
    @Override
2075
    public void getFeatureSet(Observer observer) throws DataException {
2076
        checkNotInAppendMode();
2077
        this.getFeatureSet(null, observer);
2078
    }
2079

    
2080
    @Override
2081
    public void getFeatureSet(FeatureQuery query, Observer observer)
2082
        throws DataException {
2083
        class LoadInBackGround implements Runnable {
2084

    
2085
            private final FeatureStore store;
2086
            private final FeatureQuery query;
2087
            private final Observer observer;
2088

    
2089
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2090
                Observer observer) {
2091
                this.store = store;
2092
                this.query = query;
2093
                this.observer = observer;
2094
            }
2095

    
2096
            void notify(FeatureStoreNotification theNotification) {
2097
                observer.update(store, theNotification);
2098
            }
2099

    
2100
            @Override
2101
            public void run() {
2102
                FeatureSet set = null;
2103
                try {
2104
                    set = store.getFeatureSet(query);
2105
                    notify(new DefaultFeatureStoreNotification(store,
2106
                        FeatureStoreNotification.LOAD_FINISHED, set));
2107
                } catch (Exception e) {
2108
                    notify(new DefaultFeatureStoreNotification(store,
2109
                        FeatureStoreNotification.LOAD_FINISHED, e));
2110
                } finally {
2111
                    dispose(set);
2112
                }
2113
            }
2114
        }
2115

    
2116
        checkNotInAppendMode();
2117
        if (query == null) {
2118
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2119
        }
2120
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2121
        Thread thread = new Thread(task, "Load Feature Set in background");
2122
        thread.start();
2123
    }
2124

    
2125
    @Override
2126
    public Feature getFeatureByReference(FeatureReference reference)
2127
        throws DataException {
2128
        checkNotInAppendMode();
2129
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
2130
        FeatureType featureType;
2131
        if (ref.getFeatureTypeId() == null) {
2132
            featureType = this.getDefaultFeatureType();
2133
        } else {
2134
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2135
        }
2136
        return this.getFeatureByReference(reference, featureType);
2137
    }
2138

    
2139
    @Override
2140
    public Feature getFeatureByReference(FeatureReference reference,
2141
        FeatureType featureType) throws DataException {
2142
        checkNotInAppendMode();
2143
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2144
        if (this.mode == MODE_FULLEDIT) {
2145
            Feature f = featureManager.get(reference, this, featureType);
2146
            if (f != null) {
2147
                return f;
2148
            }
2149
        }
2150

    
2151
        FeatureType sourceFeatureType = featureType;
2152
        if (!this.transforms.isEmpty()) {
2153
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2154
        }
2155
        // TODO comprobar que el id es de este store
2156

    
2157
        DefaultFeature feature =
2158
            new DefaultFeature(this,
2159
                this.provider.getFeatureProviderByReference(
2160
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2161

    
2162
        if (!this.transforms.isEmpty()) {
2163
            return this.transforms.applyTransform(feature, featureType);
2164
        }
2165
        return feature;
2166
    }
2167

    
2168
    //
2169
    // ====================================================================
2170
    // Gestion de features
2171
    //
2172

    
2173
    private FeatureType fixFeatureType(DefaultFeatureType type)
2174
        throws DataException {
2175
        FeatureType original = this.getDefaultFeatureType();
2176

    
2177
        if ((type == null) || type.equals(original)) {
2178
            return original;
2179
        } else {
2180
            if (!type.isSubtypeOf(original)) {
2181
                Iterator iter = this.getFeatureTypes().iterator();
2182
                FeatureType tmpType;
2183
                boolean found = false;
2184
                while (iter.hasNext()) {
2185
                    tmpType = (FeatureType) iter.next();
2186
                    if (type.equals(tmpType)) {
2187
                        return type;
2188

    
2189
                    } else
2190
                        if (type.isSubtypeOf(tmpType)) {
2191
                            found = true;
2192
                            original = tmpType;
2193
                            break;
2194
                        }
2195

    
2196
                }
2197
                if (!found) {
2198
                    throw new IllegalFeatureTypeException(getName());
2199
                }
2200
            }
2201
        }
2202

    
2203
        // Checks that type has all fields of pk
2204
        // else add the missing attributes at the end.
2205
        if (!original.hasOID()) {
2206
            // Gets original pk attributes
2207
            DefaultEditableFeatureType edOriginal =
2208
                (DefaultEditableFeatureType) original.getEditable();
2209
            FeatureAttributeDescriptor orgAttr;
2210
            Iterator edOriginalIter = edOriginal.iterator();
2211
            while (edOriginalIter.hasNext()) {
2212
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2213
                if (!orgAttr.isPrimaryKey()) {
2214
                    edOriginalIter.remove();
2215
                }
2216
            }
2217

    
2218
            // Checks if all pk attributes are in type
2219
            Iterator typeIterator;
2220
            edOriginalIter = edOriginal.iterator();
2221
            FeatureAttributeDescriptor attr;
2222
            while (edOriginalIter.hasNext()) {
2223
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2224
                typeIterator = type.iterator();
2225
                while (typeIterator.hasNext()) {
2226
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2227
                    if (attr.getName().equals(orgAttr.getName())) {
2228
                        edOriginalIter.remove();
2229
                        break;
2230
                    }
2231
                }
2232
            }
2233

    
2234
            // add missing pk attributes if any
2235
            if (edOriginal.size() > 0) {
2236
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2237
                DefaultEditableFeatureType edType =
2238
                    (DefaultEditableFeatureType) original.getEditable();
2239
                edType.clear();
2240
                edType.addAll(type);
2241
                edType.addAll(edOriginal);
2242
                if (!isEditable) {
2243
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2244
                }
2245
            }
2246

    
2247
        }
2248

    
2249
        return type;
2250
    }
2251

    
2252
    @Override
2253
    public void validateFeatures(int mode) throws DataException {
2254
        FeatureSet collection = null;
2255
        DisposableIterator iter = null;
2256
        try {
2257
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2258
            if( rules==null || rules.isEmpty() ) {
2259
                return;
2260
            }
2261
            checkNotInAppendMode();
2262
            collection = this.getFeatureSet();
2263
            iter = collection.fastIterator();
2264
            long previousVersionOfUpdate = currentVersionOfUpdate();
2265
            while (iter.hasNext()) {
2266
                ((DefaultFeature) iter.next()).validate(mode);
2267
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2268
                    throw new ConcurrentDataModificationException(getName());
2269
                }
2270
            }
2271
        } catch (Exception e) {
2272
            throw new ValidateFeaturesException(e, getName());
2273
        } finally {
2274
            DisposeUtils.disposeQuietly(iter);
2275
            DisposeUtils.disposeQuietly(collection);
2276
        }
2277
    }
2278

    
2279
    @Override
2280
    public FeatureType getDefaultFeatureType() throws DataException {
2281
        try {
2282

    
2283
            if (isEditing()) {
2284
                FeatureType auxFeatureType =
2285
                    featureTypeManager.getType(defaultFeatureType.getId());
2286
                if (auxFeatureType != null) {
2287
                    return avoidEditable(auxFeatureType);
2288
                }
2289
            }
2290
            FeatureType type = this.transforms.getDefaultFeatureType();
2291
                if (type != null) {
2292
                return avoidEditable(type);
2293
                }
2294

    
2295
            return avoidEditable(defaultFeatureType);
2296

    
2297
        } catch (Exception e) {
2298
            throw new GetFeatureTypeException(e, getName());
2299
        }
2300
    }
2301
    
2302
    private FeatureType avoidEditable(FeatureType ft) {
2303
        if (ft instanceof EditableFeatureType) {
2304
            return ((EditableFeatureType) ft).getNotEditableCopy();
2305
        } else {
2306
            return ft;
2307
        }
2308
    }
2309

    
2310
    @Override
2311
    public FeatureType getFeatureType(String featureTypeId)
2312
        throws DataException {
2313
        if (featureTypeId == null) {
2314
            return this.getDefaultFeatureType();
2315
        }
2316
        try {
2317
            if (isEditing()) {
2318
                FeatureType auxFeatureType =
2319
                    featureTypeManager.getType(featureTypeId);
2320
                if (auxFeatureType != null) {
2321
                    return auxFeatureType;
2322
                }
2323
            }
2324
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2325
            if (type != null) {
2326
                return type;
2327
            }
2328
            Iterator iter = this.featureTypes.iterator();
2329
            while (iter.hasNext()) {
2330
                type = (FeatureType) iter.next();
2331
                if (type.getId().equals(featureTypeId)) {
2332
                    return type;
2333
                }
2334
            }
2335
            return null;
2336
        } catch (Exception e) {
2337
            throw new GetFeatureTypeException(e, getName());
2338
        }
2339
    }
2340

    
2341
    public FeatureType getProviderDefaultFeatureType() {
2342
        return defaultFeatureType;
2343
    }
2344

    
2345
    @Override
2346
    public List getFeatureTypes() throws DataException {
2347
        try {
2348
            List types;
2349
            if (isEditing()) {
2350
                types = new ArrayList();
2351
                Iterator it = featureTypes.iterator();
2352
                while (it.hasNext()) {
2353
                    FeatureType type = (FeatureType) it.next();
2354
                    FeatureType typeaux =
2355
                        featureTypeManager.getType(type.getId());
2356
                    if (typeaux != null) {
2357
                        types.add(typeaux);
2358
                    } else {
2359
                        types.add(type);
2360
                    }
2361
                }
2362
                it = featureTypeManager.newsIterator();
2363
                while (it.hasNext()) {
2364
                    FeatureType type = (FeatureType) it.next();
2365
                    types.add(type);
2366
                }
2367
            } else {
2368
                types = this.transforms.getFeatureTypes();
2369
                if (types == null) {
2370
                    types = featureTypes;
2371
                }
2372
            }
2373
            return Collections.unmodifiableList(types);
2374
        } catch (Exception e) {
2375
            throw new GetFeatureTypeException(e, getName());
2376
        }
2377
    }
2378

    
2379
    public List getProviderFeatureTypes() throws DataException {
2380
        return Collections.unmodifiableList(this.featureTypes);
2381
    }
2382

    
2383
    @Override
2384
    public Feature createFeature(FeatureProvider data) throws DataException {
2385
        DefaultFeature feature = new DefaultFeature(this, data);
2386
        return feature;
2387
    }
2388

    
2389
    public Feature createFeature(FeatureProvider data, FeatureType type)
2390
        throws DataException {
2391
        // FIXME: falta por implementar
2392
        // Comprobar si es un subtipo del feature de data
2393
        // y construir un feature usando el subtipo.
2394
        // Probablemente requiera generar una copia del data.
2395
        throw new NotYetImplemented();
2396
    }
2397

    
2398
    @Override
2399
    public EditableFeature createNewFeature(FeatureType type,
2400
        Feature defaultValues) throws DataException {
2401
        try {
2402
            FeatureProvider data = createNewFeatureProvider(type);
2403
            DefaultEditableFeature feature =
2404
                new DefaultEditableFeature(this, data);
2405
            feature.initializeValues(defaultValues);
2406
            data.setNew(true);
2407

    
2408
            return feature;
2409
        } catch (Exception e) {
2410
            throw new CreateFeatureException(e, getName());
2411
        }
2412
    }
2413

    
2414
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2415
        throws DataException {
2416
        type = this.fixFeatureType((DefaultFeatureType) type);
2417
        FeatureProvider data = this.provider.createFeatureProvider(type);
2418
        data.setNew(true);
2419
        if (type.hasOID() && (data.getOID() == null)) {
2420
            data.setOID(this.provider.createNewOID());
2421
        } else {
2422
            data.setOID(this.getTemporalOID());
2423
        }
2424
        return data;
2425

    
2426
    }
2427

    
2428
    @Override
2429
    public EditableFeature createNewFeature(FeatureType type,
2430
        boolean defaultValues) throws DataException {
2431
        try {
2432
            FeatureProvider data = createNewFeatureProvider(type);
2433
            DefaultEditableFeature feature =
2434
                new DefaultEditableFeature(this, data);
2435
            if (defaultValues) {
2436
                feature.initializeValues();
2437
            }
2438
            return feature;
2439
        } catch (Exception e) {
2440
            throw new CreateFeatureException(e, getName());
2441
        }
2442
    }
2443

    
2444
    @Override
2445
    public EditableFeature createNewFeature(boolean defaultValues)
2446
        throws DataException {
2447
        return this.createNewFeature(this.getDefaultFeatureType(),
2448
            defaultValues);
2449
    }
2450

    
2451
    @Override
2452
    public EditableFeature createNewFeature() throws DataException {
2453
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2454
    }
2455

    
2456
    @Override
2457
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2458
        FeatureType ft = this.getDefaultFeatureType();
2459
        EditableFeature f = this.createNewFeature(ft, false);
2460
                for( FeatureAttributeDescriptor desc : ft ) {
2461
                        try {
2462
                                f.set(desc.getName(), defaultValues.get(desc.getName()));
2463
                        } catch(Throwable th) {
2464
                                // Ignore
2465
                        }
2466
                }
2467
        return f;
2468
    }
2469

    
2470
    @Override
2471
    public EditableFeatureType createFeatureType() {
2472
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2473
        return ftype;
2474
    }
2475

    
2476
    @Override
2477
    public EditableFeatureType createFeatureType(String id) {
2478
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2479
        return ftype;
2480
    }
2481

    
2482
    //
2483
    // ====================================================================
2484
    // Index related methods
2485
    //
2486

    
2487
    @Override
2488
    public FeatureIndexes getIndexes() {
2489
        return this.indexes;
2490
    }
2491

    
2492
    @Override
2493
    public FeatureIndex createIndex(FeatureType featureType,
2494
        String attributeName, String indexName) throws DataException {
2495
        return createIndex(null, featureType, attributeName, indexName);
2496
    }
2497

    
2498
    @Override
2499
    public FeatureIndex createIndex(String indexTypeName,
2500
        FeatureType featureType, String attributeName, String indexName)
2501
        throws DataException {
2502

    
2503
        return createIndex(indexTypeName, featureType, attributeName,
2504
            indexName, false, null);
2505
    }
2506

    
2507
    @Override
2508
    public FeatureIndex createIndex(FeatureType featureType,
2509
        String attributeName, String indexName, Observer observer)
2510
        throws DataException {
2511
        return createIndex(null, featureType, attributeName, indexName,
2512
            observer);
2513
    }
2514

    
2515
    @Override
2516
    public FeatureIndex createIndex(String indexTypeName,
2517
        FeatureType featureType, String attributeName, String indexName,
2518
        final Observer observer) throws DataException {
2519

    
2520
        return createIndex(indexTypeName, featureType, attributeName,
2521
            indexName, true, observer);
2522
    }
2523

    
2524
    private FeatureIndex createIndex(String indexTypeName,
2525
        FeatureType featureType, String attributeName, String indexName,
2526
        boolean background, final Observer observer) throws DataException {
2527

    
2528
        checkNotInAppendMode();
2529
        FeatureIndexProviderServices index;
2530
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2531
                featureType, indexName,
2532
                featureType.getAttributeDescriptor(attributeName));
2533

    
2534
        try {
2535
            index.fill(background, observer);
2536
        } catch (FeatureIndexException e) {
2537
            throw new InitializeException(index.getName(), e);
2538
        }
2539

    
2540
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2541
        return index;
2542
    }
2543

    
2544
    //
2545
    // ====================================================================
2546
    // Transforms related methods
2547
    //
2548

    
2549
    @Override
2550
    public FeatureStoreTransforms getTransforms() {
2551
        return this.transforms;
2552
    }
2553

    
2554
    @Override
2555
    public FeatureQuery createFeatureQuery() {
2556
        return new DefaultFeatureQuery();
2557
    }
2558
    
2559
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
2560
        FeatureQuery query = null;
2561
        if( filter!=null ) {
2562
            query = this.createFeatureQuery();
2563
            query.setFilter(filter);
2564
        }
2565
        if( !StringUtils.isEmpty(sortBy) ) {
2566
            if( query == null ) {
2567
                query = this.createFeatureQuery();
2568
            }
2569
            String[] attrnames;
2570
            if( sortBy.contains(",") ) {
2571
                attrnames = StringUtils.split(sortBy, ",");
2572
            } else {
2573
                attrnames = new String[] { sortBy };
2574
            }
2575
            for (String attrname : attrnames) {
2576
                attrname = attrname.trim();
2577
                if( attrname.startsWith("-") ) {
2578
                    query.getOrder().add(sortBy.substring(1).trim(), false);
2579
                } else if( attrname.endsWith("-") ) { 
2580
                    query.getOrder().add(sortBy.substring(0,sortBy.length()-1).trim(), false);
2581
                } else if( attrname.startsWith("+") ) {
2582
                    query.getOrder().add(sortBy.substring(1).trim(), true);
2583
                } else if( attrname.endsWith("-") ) { 
2584
                    query.getOrder().add(sortBy.substring(0,sortBy.length()-1).trim(), true);
2585
                } else {
2586
                    query.getOrder().add(sortBy, asc);
2587
                }
2588
            }
2589
        }
2590
        if( query != null ) {
2591
            query.retrievesAllAttributes();
2592
        }
2593
        return query;
2594
    }
2595
    
2596
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
2597
        if( StringUtils.isBlank(filter) ) {
2598
            return this.createFeatureQuery(
2599
                    (Expression)null, 
2600
                    sortBy, 
2601
                    asc
2602
            );
2603
        } else {
2604
            return this.createFeatureQuery(
2605
                    ExpressionUtils.createExpression(filter), 
2606
                    sortBy, 
2607
                    asc
2608
            );
2609
        }
2610
    }
2611
    
2612
    @Override
2613
    public DataQuery createQuery() {
2614
        return createFeatureQuery();
2615
    }
2616

    
2617
    //
2618
    // ====================================================================
2619
    // UndoRedo related methods
2620
    //
2621

    
2622
    @Override
2623
    public boolean canRedo() {
2624
        return commands.canRedo();
2625
    }
2626

    
2627
    @Override
2628
    public boolean canUndo() {
2629
        return commands.canUndo();
2630
    }
2631

    
2632
    @Override
2633
    public void redo(int num) throws RedoException {
2634
        for (int i = 0; i < num; i++) {
2635
            redo();
2636
        }
2637
    }
2638

    
2639
    @Override
2640
    public void undo(int num) throws UndoException {
2641
        for (int i = 0; i < num; i++) {
2642
            undo();
2643
        }
2644
    }
2645

    
2646
    //
2647
    // ====================================================================
2648
    // Metadata related methods
2649
    //
2650

    
2651
    @Override
2652
    public Object getMetadataID() {
2653
        return this.provider.getSourceId();
2654
    }
2655

    
2656
    @Override
2657
    public void delegate(DynObject dynObject) {
2658
        this.metadata.delegate(dynObject);
2659
    }
2660

    
2661
    @Override
2662
    public DynClass getDynClass() {
2663
        return this.metadata.getDynClass();
2664
    }
2665

    
2666
    @Override
2667
    public Object getDynValue(String name) throws DynFieldNotFoundException {
2668
        try {
2669
            if (this.transforms.hasDynValue(name)) {
2670
                return this.transforms.getDynValue(name);
2671
            }
2672
            if (this.metadata.hasDynValue(name)) {
2673
                return this.metadata.getDynValue(name);
2674
            }
2675
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2676
                return this.provider.getProviderName();
2677
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2678
                return this.provider.getSourceId();
2679
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2680
                try {
2681
                    return this.getDefaultFeatureType();
2682
                } catch (DataException e) {
2683
                    return null;
2684
                }
2685
            }
2686
            return this.metadata.getDynValue(name);
2687
        } catch(Exception ex ) {
2688
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
2689
            return null;
2690
        }
2691
    }
2692

    
2693
    @Override
2694
    public boolean hasDynValue(String name) {
2695
        if (this.transforms.hasDynValue(name)) {
2696
            return true;
2697
        }
2698
        return this.metadata.hasDynValue(name);
2699
    }
2700

    
2701
    @Override
2702
    public boolean hasDynMethod(String name) {
2703
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2704
    }
2705

    
2706
    @Override
2707
    public void implement(DynClass dynClass) {
2708
        this.metadata.implement(dynClass);
2709
    }
2710

    
2711
    @Override
2712
    public Object invokeDynMethod(String name, Object[] args)
2713
        throws DynMethodException {
2714
        return this.metadata.invokeDynMethod(this, name, args);
2715
    }
2716

    
2717
    @Override
2718
    public Object invokeDynMethod(int code, Object[] args)
2719
        throws DynMethodException {
2720
        return this.metadata.invokeDynMethod(this, code, args);
2721
    }
2722

    
2723
    @Override
2724
    public void setDynValue(String name, Object value)
2725
        throws DynFieldNotFoundException {
2726
                if( this.transforms.hasDynValue(name) ) {
2727
                        this.transforms.setDynValue(name, value);
2728
                        return;
2729
                }
2730
        this.metadata.setDynValue(name, value);
2731

    
2732
    }
2733

    
2734
    /*
2735
     * (non-Javadoc)
2736
     *
2737
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2738
     */
2739
    @Override
2740
    public Set getMetadataChildren() {
2741
        return this.metadataChildren;
2742
    }
2743

    
2744
    /*
2745
     * (non-Javadoc)
2746
     *
2747
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2748
     */
2749
    @Override
2750
    public String getMetadataName() {
2751
        return this.provider.getProviderName();
2752
    }
2753

    
2754
    public FeatureTypeManager getFeatureTypeManager() {
2755
        return this.featureTypeManager;
2756
    }
2757

    
2758
    @Override
2759
    public long getFeatureCount() throws DataException {
2760
        if (featureCount == null) {
2761
            featureCount = this.provider.getFeatureCount();
2762
        }
2763
        if (this.isEditing()) {
2764
            if(this.isAppending()) {
2765
                try{
2766
                    throw new IllegalStateException();
2767
                } catch(IllegalStateException e) {
2768
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
2769
                }
2770
                return -1;
2771
            } else {
2772
                return featureCount
2773
                    + this.featureManager.getDeltaSize();
2774
            }
2775
        }
2776
        return featureCount;
2777
    }
2778

    
2779
    private Long getTemporalOID() {
2780
        return this.temporalOid++;
2781
    }
2782

    
2783
    @Override
2784
    public FeatureType getProviderFeatureType(String featureTypeId) {
2785
        if (featureTypeId == null) {
2786
            return this.defaultFeatureType;
2787
        }
2788
        FeatureType type;
2789
        Iterator iter = this.featureTypes.iterator();
2790
        while (iter.hasNext()) {
2791
            type = (FeatureType) iter.next();
2792
            if (type.getId().equals(featureTypeId)) {
2793
                return type;
2794
            }
2795
        }
2796
        return null;
2797
    }
2798

    
2799
    @Override
2800
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2801
        return ((DefaultFeature) feature).getData();
2802
    }
2803

    
2804
    @Override
2805
    public DataStore getStore() {
2806
        return this;
2807
    }
2808

    
2809
    @Override
2810
    public FeatureStore getFeatureStore() {
2811
        return this;
2812
    }
2813

    
2814
    @Override
2815
    public void createCache(String name, DynObject parameters)
2816
        throws DataException {
2817
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2818
        if (cache == null) {
2819
            throw new CreateException("FeaureCacheProvider", null);
2820
        }
2821
        cache.apply(this, provider);
2822
        provider = cache;
2823

    
2824
        featureCount = null;
2825
    }
2826

    
2827
    @Override
2828
    public FeatureCache getCache() {
2829
        return cache;
2830
    }
2831

    
2832
    @Override
2833
    public void clear() {
2834
        if (metadata != null) {
2835
            metadata.clear();
2836
        }
2837
    }
2838

    
2839
    @Override
2840
    public String getName() {
2841
        if( this.provider != null ) {
2842
            return this.provider.getName();
2843
        }
2844
        if( this.parameters instanceof HasAFile ) {
2845
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
2846
        }
2847
        return "unknow";
2848
    }
2849

    
2850
    @Override
2851
    public String getFullName() {
2852
        try {
2853
            if( this.provider!=null ) {
2854
                return this.provider.getFullName();
2855
            }
2856
            if( this.parameters instanceof HasAFile ) {
2857
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
2858
            }
2859
            return null;
2860
        } catch(Throwable th) {
2861
            return null;
2862
        }
2863
    }
2864

    
2865
    @Override
2866
    public String getProviderName() {
2867
        if( this.provider!=null ) {
2868
            return this.provider.getProviderName();
2869
        }
2870
        if( this.parameters != null ) {
2871
            return this.parameters.getDataStoreName();
2872
        }
2873
        return null;
2874

    
2875
    }
2876

    
2877
    @Override
2878
    public boolean isKnownEnvelope() {
2879
        return this.provider.isKnownEnvelope();
2880
    }
2881

    
2882
    @Override
2883
    public boolean hasRetrievedFeaturesLimit() {
2884
        return this.provider.hasRetrievedFeaturesLimit();
2885
    }
2886

    
2887
    @Override
2888
    public int getRetrievedFeaturesLimit() {
2889
        return this.provider.getRetrievedFeaturesLimit();
2890
    }
2891

    
2892
    @Override
2893
    public Interval getInterval() {
2894
        if( this.timeSupport!=null ) {
2895
            return this.timeSupport.getInterval();
2896
        }
2897
        try {
2898
            FeatureType type = this.getDefaultFeatureType();
2899
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
2900
            if( attr!=null ) {
2901
                Interval interval = attr.getInterval();
2902
                if( interval!=null ) {
2903
                    return interval;
2904
                }
2905
            }
2906
        } catch (DataException ex) {
2907
        }
2908
        return this.provider.getInterval();
2909
    }
2910

    
2911
    @Override
2912
    public Collection getTimes() {
2913
        if( this.timeSupport!=null ) {
2914
            return this.timeSupport.getTimes();
2915
        }
2916
        return this.provider.getTimes();
2917
    }
2918

    
2919
    @Override
2920
    public Collection getTimes(Interval interval) {
2921
        if( this.timeSupport!=null ) {
2922
            return this.timeSupport.getTimes(interval);
2923
        }
2924
        return this.provider.getTimes(interval);
2925
    }
2926

    
2927
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
2928
        if( this.isEditing() ) {
2929
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
2930
        }
2931
        if( !this.transforms.isEmpty() ) {
2932
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
2933
        }
2934
        FeatureType ft = this.defaultFeatureType;
2935
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
2936
        if( attr == null ) {
2937
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
2938
        }
2939
        EditableFeatureType eft = ft.getEditable();
2940
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
2941
        if( attr != null ) {
2942
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
2943
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
2944
            }
2945
            eft.remove(attr.getName());
2946
        }
2947
        EditableFeatureAttributeDescriptor attrTime = eft.add(
2948
            timeSupport.getAttributeName(), 
2949
            timeSupport.getDataType()
2950
        );
2951
        attrTime.setIsTime(true);
2952
        attrTime.setFeatureAttributeEmulator(timeSupport);
2953
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
2954
        this.defaultFeatureType = eft.getNotEditableCopy();
2955
        
2956
        this.timeSupport = timeSupport;
2957
    }
2958

    
2959
    @Override
2960
    @SuppressWarnings("CloneDoesntCallSuperClone")
2961
    public Object clone() throws CloneNotSupportedException {
2962

    
2963
        DataStoreParameters dsp = getParameters();
2964

    
2965
        DefaultFeatureStore cloned_store = null;
2966

    
2967
        try {
2968
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2969
                openStore(this.getProviderName(), dsp);
2970
            if (transforms != null) {
2971
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2972
                cloned_store.transforms.setStoreForClone(cloned_store);
2973
            }
2974
        } catch (Exception e) {
2975
            throw new CloneException(e);
2976
        }
2977
        return cloned_store;
2978

    
2979
    }
2980

    
2981
    @Override
2982
    public Feature getFeature(DynObject dynobject) {
2983
        if (dynobject instanceof DynObjectFeatureFacade){
2984
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2985
            return f;
2986
        }
2987
        return null;
2988
    }
2989

    
2990
    @Override
2991
    public Iterator iterator() {
2992
        try {
2993
            return this.getFeatureSet().fastIterator();
2994
        } catch (DataException ex) {
2995
            throw new RuntimeException(ex);
2996
        }
2997
    }
2998

    
2999
    @Override
3000
    public ExpressionBuilder createExpressionBuilder() {
3001
        ExpressionBuilder builder;
3002
        builder = ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
3003
        return builder;
3004
    }
3005

    
3006
    @Override
3007
    public ExpressionBuilder createExpression() {
3008
        return createExpressionBuilder();
3009
    }
3010

    
3011
    public FeatureSet features() throws DataException {
3012
        // This is to avoid jython to create a property with this name
3013
        // to access method getFeatures.
3014
        return this.getFeatureSet();
3015
    }
3016

    
3017
    @Override
3018
    public DataStoreProviderFactory getProviderFactory() {
3019
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3020
        return factory;
3021
    }
3022

    
3023
    @Override
3024
    public void useCache(String providerName, DynObject parameters) throws DataException {
3025
        throw new UnsupportedOperationException();
3026
    }
3027

    
3028
    @Override
3029
    public boolean isBroken() {
3030
        return this.state.isBroken();
3031
    }
3032

    
3033
    @Override
3034
    public Throwable getBreakingsCause() {
3035
            return this.state.getBreakingsCause();
3036
    }
3037

    
3038
    @Override
3039
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3040
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3041
      if( !factory.supportNumericOID() ) {
3042
          return null;
3043
      }
3044
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3045
      return wrappedIndex;
3046
  }
3047

    
3048
    @Override
3049
    public FeatureReference getFeatureReference(String code) {
3050
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
3051
        return featureReference;
3052
    }
3053

    
3054
    @Override
3055
    public long getPendingChangesCount() {
3056
        if( this.featureManager==null ) {
3057
            return 0;
3058
        }
3059
        return this.featureManager.getPendingChangesCount();
3060
    }
3061

    
3062
    @Override
3063
    public ResourcesStorage getResourcesStorage() {
3064
        ResourcesStorage resourcesStorage;
3065
        try {
3066
            resourcesStorage = this.provider.getResourcesStorage();
3067
            if( resourcesStorage!=null ) {
3068
                return resourcesStorage;
3069
            }
3070
        } catch(Throwable th) {
3071
            
3072
        }
3073
        try {
3074
            DataServerExplorer explorer = this.getExplorer();
3075
            if( explorer==null ) {
3076
                return null;
3077
            }
3078
            return this.getExplorer().getResourcesStorage(this);
3079
        } catch (Exception ex) {
3080
            LOGGER.warn("Can't create resources storage",ex);
3081
            return null;
3082
        }
3083
    }
3084

    
3085
    @Override
3086
    public StoresRepository getStoresRepository() {
3087
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3088
        StoresRepository localRepository = this.provider.getStoresRepository();
3089
        if( localRepository==null ) {
3090
            return mainRepository;
3091
        }
3092
        StoresRepository repository = new BaseStoresRepository(this.getName());
3093
        repository.addRepository(localRepository);
3094
        repository.addRepository(mainRepository);
3095
        return repository;
3096
    }
3097

    
3098
    @Override
3099
    public Feature getSampleFeature() {
3100
            Feature sampleFeature;
3101
            try {
3102
                FeatureSelection theSelection = this.getFeatureSelection();
3103
                if( theSelection!=null && !theSelection.isEmpty() ) {
3104
                    sampleFeature = theSelection.first();
3105
                } else {
3106
                    sampleFeature = this.first();
3107
                }
3108
                if( sampleFeature==null ) {
3109
                    sampleFeature = this.createNewFeature();
3110
                }
3111
            } catch (DataException ex) {
3112
                return null;
3113
            }
3114
            return sampleFeature;
3115
    }
3116

    
3117
    @Override
3118
    public boolean supportReferences() {
3119
        try {
3120
            return this.getDefaultFeatureType().supportReferences();
3121
        } catch (Exception ex) {
3122
            return false;
3123
        }
3124
    }
3125

    
3126
    @Override
3127
    public boolean isTemporary() {
3128
        if( this.provider==null ) {
3129
            return true;
3130
        }
3131
        return this.provider.isTemporary();
3132
    }
3133
    
3134
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3135
        // FIXME this don't work for Store.fType.size() > 1
3136
        FeatureTypeManager manager = this.featureTypeManager;
3137
         if (manager==null) {
3138
             return null;
3139
         }
3140
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3141
         if (originalFeatureType==null) {
3142
             return null;
3143
         }
3144
         return originalFeatureType.getCopy();
3145
    }
3146
}