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

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.defaultFeatureType)) {
1238
                notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
1239
                FeatureType theType = type.getNotEditableCopy();
1240
                if( defaultFeatureType.getId().equals(theType.getId()) ) {
1241
                    defaultFeatureType = theType;
1242
                }
1243
                List newtypes = new ArrayList();
1244
                for (FeatureType featureType : this.featureTypes) {
1245
                    if( featureType.getId().equals(theType.getId()) ) {
1246
                        newtypes.add(theType);
1247
                    } else {
1248
                        newtypes.add(featureType);
1249
                    }                    
1250
                }
1251
                this.featureTypes = newtypes;
1252
                saveDALFile();
1253
                notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1254
                return ;
1255
            }
1256
            boolean typehasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1257
            if (typehasStrongChanges) {
1258
                checkInEditingMode();
1259
            }  else if(this.isAppending()) {
1260
                throw new NeedEditingModeException(this.getName());
1261
            }
1262
            // FIXME: Comprobar que es un featureType aceptable.
1263
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
1264
            newVersionOfUpdate();
1265
            
1266
            FeatureType oldt = type.getSource().getCopy();
1267
            FeatureType newt = type.getCopy();
1268
            commands.update(newt, oldt);
1269
            if (typehasStrongChanges) { 
1270
                hasStrongChanges = true;
1271
            }
1272
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1273
        } catch (Exception e) {
1274
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1275
        }
1276
    }
1277

    
1278
    @Override
1279
    public void delete(Feature feature) throws DataException {
1280
        this.commands.delete(feature);
1281
    }
1282

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

    
1292
            //Update the featureManager and the spatialManager
1293
            featureManager.delete(feature.getReference());
1294
            spatialManager.deleteFeature(feature);
1295

    
1296
            newVersionOfUpdate();
1297
            hasStrongChanges = true;
1298
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1299
        } catch (Exception e) {
1300
            throw new StoreDeleteFeatureException(e, this.getName());
1301
        }
1302
    }
1303

    
1304
    private static EditableFeature lastChangedFeature = null;
1305

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

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

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

    
1340
    synchronized public void doInsert(EditableFeature feature)
1341
        throws DataException {
1342
        checkIsOwnFeature(feature);
1343

    
1344
        waitForIndexes();
1345

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

    
1358

    
1359
        featureManager.add(newFeature);
1360
        spatialManager.insertFeature(newFeature);
1361

    
1362
        hasStrongChanges = true;
1363
        hasInserts = true;
1364
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1365
    }
1366

    
1367
    @Override
1368
    public void update(EditableFeature feature)
1369
    throws DataException {
1370
        if ((feature).getSource() == null) {
1371
            insert(feature);
1372
            return;
1373
        }
1374
        commands.update(feature, feature.getSource());
1375
    }
1376

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

    
1391
            //Update the featureManager and the spatialManager
1392
            Feature newf = feature.getNotEditableCopy();
1393
            featureManager.update(newf, oldFeature);
1394
            spatialManager.updateFeature(newf, oldFeature);
1395

    
1396
            hasStrongChanges = true;
1397
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1398
        } catch (Exception e) {
1399
            throw new StoreUpdateFeatureException(e, this.getName());
1400
        }
1401
    }
1402

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

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

    
1433
    @Override
1434
    public List getRedoInfos() {
1435
        if (isEditing() && (commands != null)) {
1436
            return commands.getRedoInfos();
1437
        } else {
1438
            return null;
1439
        }
1440
    }
1441

    
1442
    @Override
1443
    public List getUndoInfos() {
1444
        if (isEditing() && (commands != null)) {
1445
            return commands.getUndoInfos();
1446
        } else {
1447
            return null;
1448
        }
1449
    }
1450

    
1451
    public synchronized FeatureCommandsStack getCommandsStack()
1452
        throws DataException {
1453
        checkInEditingMode();
1454
        return commands;
1455
    }
1456

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

    
1467
            case MODE_APPEND:
1468
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1469
                provider.abortAppend();
1470
                exitEditingMode();
1471
                ((FeatureSelection) this.getSelection()).deselectAll();
1472
                updateIndexes();
1473
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1474

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

    
1493
    @Override
1494
    synchronized public void finishEditing() throws DataException {
1495
        LOGGER.debug("finish editing of mode: {}", mode);
1496
        try {
1497

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

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

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

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

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

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

    
1676
        case MODE_APPEND:
1677
          this.provider.endAppend();
1678
          exitEditingMode();
1679
          invalidateIndexes();
1680
          this.provider.beginAppend();
1681
          hasInserts = false;
1682
          break;
1683

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

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

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

    
1723
        case MODE_APPEND:
1724
                return true;
1725

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

    
1740
    @Override
1741
    public void beginEditingGroup(String description)
1742
        throws NeedEditingModeException {
1743
        checkInEditingMode();
1744
        commands.startComplex(description);
1745
    }
1746

    
1747
    @Override
1748
    public void endEditingGroup() throws NeedEditingModeException {
1749
        checkInEditingMode();
1750
        commands.endComplex();
1751
    }
1752

    
1753
    @Override
1754
    public boolean isAppendModeSupported() {
1755
        return this.provider.supportsAppendMode();
1756
    }
1757

    
1758
    @Override
1759
    public void export(DataServerExplorer explorer, String provider,
1760
        NewFeatureStoreParameters params) throws DataException {
1761

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

    
1776
            }
1777
            explorer.add(provider, params, true);
1778

    
1779
            DataManager manager = DALLocator.getDataManager();
1780
            target = (FeatureStore) manager.openStore(provider, params);
1781
            FeatureType targetType = target.getDefaultFeatureType();
1782

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

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

    
1851
    @Override
1852
    public DataSet getDataSet() throws DataException {
1853
        checkNotInAppendMode();
1854
        FeatureQuery query =
1855
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1856
        return new DefaultFeatureSet(this, query);
1857
    }
1858

    
1859
    @Override
1860
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1861
        checkNotInAppendMode();
1862
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1863
    }
1864

    
1865
    @Override
1866
    public void getDataSet(Observer observer) throws DataException {
1867
        checkNotInAppendMode();
1868
        this.getFeatureSet(null, observer);
1869
    }
1870

    
1871
    @Override
1872
    public void getDataSet(DataQuery dataQuery, Observer observer)
1873
        throws DataException {
1874
        checkNotInAppendMode();
1875
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1876
    }
1877

    
1878
    @Override
1879
    public FeatureSet getFeatureSet() throws DataException {
1880
        return this.getFeatureSet((FeatureQuery)null);
1881
    }
1882

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

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

    
1898
    @Override
1899
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
1900
        return this.getFeatureSet(filter, sortBy, true);
1901
    }
1902

    
1903
    @Override
1904
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
1905
        return this.getFeatureSet(filter, null, true);
1906
    }
1907
    
1908
    @Override
1909
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
1910
        return this.getFeatureSet(filter, sortBy, true);
1911
    }
1912

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

    
1930
    @Override
1931
    public List<Feature> getFeatures(String filter, String sortBy)  {
1932
        return this.getFeatures(filter, sortBy, true);
1933
    }
1934

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

    
1946
    @Override
1947
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
1948
        return this.getFeatures(filter, sortBy, true);
1949
    }
1950

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

    
1975
    @Override
1976
    public List<Feature> getFeatures() {
1977
        return this.getFeatures(null, 0);
1978
    }
1979

    
1980
    @Override
1981
    public Feature first() throws DataException {
1982
        return this.findFirst((FeatureQuery)null);
1983
    }
1984
    
1985
    @Override
1986
    public Feature findFirst(String filter) throws DataException {
1987
        return this.findFirst(filter, null, true);
1988
    }
1989

    
1990
    @Override
1991
    public Feature findFirst(String filter, String sortBy) throws DataException {
1992
        return this.findFirst(filter, sortBy, true);
1993
    }
1994

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

    
2006
    @Override
2007
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2008
        return this.findFirst(filter, sortBy, true);
2009
    }
2010

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

    
2036
        } catch(DataException ex) {
2037
            throw ex;
2038
        } catch(Exception ex) {
2039
            throw new RuntimeException("", ex);
2040
        }
2041
        return feature.getValue();
2042
    }
2043

    
2044
    @Override
2045
    public void accept(Visitor visitor) throws BaseException {
2046
        this.accept(visitor, null);
2047
    }
2048

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

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

    
2078
    @Override
2079
    public void getFeatureSet(Observer observer) throws DataException {
2080
        checkNotInAppendMode();
2081
        this.getFeatureSet(null, observer);
2082
    }
2083

    
2084
    @Override
2085
    public void getFeatureSet(FeatureQuery query, Observer observer)
2086
        throws DataException {
2087
        class LoadInBackGround implements Runnable {
2088

    
2089
            private final FeatureStore store;
2090
            private final FeatureQuery query;
2091
            private final Observer observer;
2092

    
2093
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2094
                Observer observer) {
2095
                this.store = store;
2096
                this.query = query;
2097
                this.observer = observer;
2098
            }
2099

    
2100
            void notify(FeatureStoreNotification theNotification) {
2101
                observer.update(store, theNotification);
2102
            }
2103

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

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

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

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

    
2155
        FeatureType sourceFeatureType = featureType;
2156
        if (!this.transforms.isEmpty()) {
2157
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2158
        }
2159
        // TODO comprobar que el id es de este store
2160

    
2161
        DefaultFeature feature =
2162
            new DefaultFeature(this,
2163
                this.provider.getFeatureProviderByReference(
2164
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2165

    
2166
        if (!this.transforms.isEmpty()) {
2167
            return this.transforms.applyTransform(feature, featureType);
2168
        }
2169
        return feature;
2170
    }
2171

    
2172
    //
2173
    // ====================================================================
2174
    // Gestion de features
2175
    //
2176

    
2177
    private FeatureType fixFeatureType(DefaultFeatureType type)
2178
        throws DataException {
2179
        FeatureType original = this.getDefaultFeatureType();
2180

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

    
2193
                    } else
2194
                        if (type.isSubtypeOf(tmpType)) {
2195
                            found = true;
2196
                            original = tmpType;
2197
                            break;
2198
                        }
2199

    
2200
                }
2201
                if (!found) {
2202
                    throw new IllegalFeatureTypeException(getName());
2203
                }
2204
            }
2205
        }
2206

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

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

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

    
2251
        }
2252

    
2253
        return type;
2254
    }
2255

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

    
2283
    @Override
2284
    public FeatureType getDefaultFeatureType() throws DataException {
2285
        try {
2286

    
2287
            if (isEditing()) {
2288
                FeatureType auxFeatureType =
2289
                    featureTypeManager.getType(defaultFeatureType.getId());
2290
                if (auxFeatureType != null) {
2291
                    return avoidEditable(auxFeatureType);
2292
                }
2293
            }
2294
            FeatureType type = this.transforms.getDefaultFeatureType();
2295
                if (type != null) {
2296
                return avoidEditable(type);
2297
                }
2298

    
2299
            return avoidEditable(defaultFeatureType);
2300

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

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

    
2345
    public FeatureType getProviderDefaultFeatureType() {
2346
        return defaultFeatureType;
2347
    }
2348

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

    
2383
    public List getProviderFeatureTypes() throws DataException {
2384
        return Collections.unmodifiableList(this.featureTypes);
2385
    }
2386

    
2387
    @Override
2388
    public Feature createFeature(FeatureProvider data) throws DataException {
2389
        DefaultFeature feature = new DefaultFeature(this, data);
2390
        return feature;
2391
    }
2392

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

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

    
2412
            return feature;
2413
        } catch (Exception e) {
2414
            throw new CreateFeatureException(e, getName());
2415
        }
2416
    }
2417

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

    
2430
    }
2431

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

    
2448
    @Override
2449
    public EditableFeature createNewFeature(boolean defaultValues)
2450
        throws DataException {
2451
        return this.createNewFeature(this.getDefaultFeatureType(),
2452
            defaultValues);
2453
    }
2454

    
2455
    @Override
2456
    public EditableFeature createNewFeature() throws DataException {
2457
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2458
    }
2459

    
2460
    @Override
2461
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2462
        FeatureType ft = this.getDefaultFeatureType();
2463
        EditableFeature f = this.createNewFeature(ft, false);
2464
        f.copyFrom(defaultValues);
2465
        return f;
2466
    }
2467

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

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

    
2480
    //
2481
    // ====================================================================
2482
    // Index related methods
2483
    //
2484

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

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

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

    
2501
        return createIndex(indexTypeName, featureType, attributeName,
2502
            indexName, false, null);
2503
    }
2504

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

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

    
2518
        return createIndex(indexTypeName, featureType, attributeName,
2519
            indexName, true, observer);
2520
    }
2521

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

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

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

    
2538
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2539
        return index;
2540
    }
2541

    
2542
    //
2543
    // ====================================================================
2544
    // Transforms related methods
2545
    //
2546

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

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

    
2615
    //
2616
    // ====================================================================
2617
    // UndoRedo related methods
2618
    //
2619

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

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

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

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

    
2644
    //
2645
    // ====================================================================
2646
    // Metadata related methods
2647
    //
2648

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

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

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

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

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

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

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

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

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

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

    
2730
    }
2731

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

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

    
2752
    public FeatureTypeManager getFeatureTypeManager() {
2753
        return this.featureTypeManager;
2754
    }
2755

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

    
2777
    private Long getTemporalOID() {
2778
        return this.temporalOid++;
2779
    }
2780

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

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

    
2802
    @Override
2803
    public DataStore getStore() {
2804
        return this;
2805
    }
2806

    
2807
    @Override
2808
    public FeatureStore getFeatureStore() {
2809
        return this;
2810
    }
2811

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

    
2822
        featureCount = null;
2823
    }
2824

    
2825
    @Override
2826
    public FeatureCache getCache() {
2827
        return cache;
2828
    }
2829

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

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

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

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

    
2873
    }
2874

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

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

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

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

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

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

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

    
2957
    @Override
2958
    @SuppressWarnings("CloneDoesntCallSuperClone")
2959
    public Object clone() throws CloneNotSupportedException {
2960

    
2961
        DataStoreParameters dsp = getParameters();
2962

    
2963
        DefaultFeatureStore cloned_store = null;
2964

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

    
2977
    }
2978

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

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

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

    
3004
    @Override
3005
    public ExpressionBuilder createExpression() {
3006
        return createExpressionBuilder();
3007
    }
3008

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

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

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

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

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

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

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

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

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

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

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

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

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