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

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

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

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

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

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

    
1302
    private static EditableFeature lastChangedFeature = null;
1303

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

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

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

    
1338
    synchronized public void doInsert(EditableFeature feature)
1339
        throws DataException {
1340
        checkIsOwnFeature(feature);
1341

    
1342
        waitForIndexes();
1343

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

    
1356

    
1357
        featureManager.add(newFeature);
1358
        spatialManager.insertFeature(newFeature);
1359

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1721
        case MODE_APPEND:
1722
                return true;
1723

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

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

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

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

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

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

    
1774
            }
1775
            explorer.add(provider, params, true);
1776

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2087
            private final FeatureStore store;
2088
            private final FeatureQuery query;
2089
            private final Observer observer;
2090

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

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

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

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

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

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

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

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

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

    
2170
    //
2171
    // ====================================================================
2172
    // Gestion de features
2173
    //
2174

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

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

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

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

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

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

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

    
2249
        }
2250

    
2251
        return type;
2252
    }
2253

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

    
2281
    @Override
2282
    public FeatureType getDefaultFeatureType() throws DataException {
2283
        try {
2284

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

    
2297
            return avoidEditable(defaultFeatureType);
2298

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

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

    
2343
    public FeatureType getProviderDefaultFeatureType() {
2344
        return defaultFeatureType;
2345
    }
2346

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

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

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

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

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

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

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

    
2428
    }
2429

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

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

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

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

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

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

    
2484
    //
2485
    // ====================================================================
2486
    // Index related methods
2487
    //
2488

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

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

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

    
2505
        return createIndex(indexTypeName, featureType, attributeName,
2506
            indexName, false, null);
2507
    }
2508

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

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

    
2522
        return createIndex(indexTypeName, featureType, attributeName,
2523
            indexName, true, observer);
2524
    }
2525

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

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

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

    
2542
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2543
        return index;
2544
    }
2545

    
2546
    //
2547
    // ====================================================================
2548
    // Transforms related methods
2549
    //
2550

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

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

    
2619
    //
2620
    // ====================================================================
2621
    // UndoRedo related methods
2622
    //
2623

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

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

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

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

    
2648
    //
2649
    // ====================================================================
2650
    // Metadata related methods
2651
    //
2652

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

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

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

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

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

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

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

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

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

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

    
2734
    }
2735

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

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

    
2756
    public FeatureTypeManager getFeatureTypeManager() {
2757
        return this.featureTypeManager;
2758
    }
2759

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

    
2781
    private Long getTemporalOID() {
2782
        return this.temporalOid++;
2783
    }
2784

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

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

    
2806
    @Override
2807
    public DataStore getStore() {
2808
        return this;
2809
    }
2810

    
2811
    @Override
2812
    public FeatureStore getFeatureStore() {
2813
        return this;
2814
    }
2815

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

    
2826
        featureCount = null;
2827
    }
2828

    
2829
    @Override
2830
    public FeatureCache getCache() {
2831
        return cache;
2832
    }
2833

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

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

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

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

    
2877
    }
2878

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

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

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

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

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

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

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

    
2961
    @Override
2962
    @SuppressWarnings("CloneDoesntCallSuperClone")
2963
    public Object clone() throws CloneNotSupportedException {
2964

    
2965
        DataStoreParameters dsp = getParameters();
2966

    
2967
        DefaultFeatureStore cloned_store = null;
2968

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

    
2981
    }
2982

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

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

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

    
3008
    @Override
3009
    public ExpressionBuilder createExpression() {
3010
        return createExpressionBuilder();
3011
    }
3012

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

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

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

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

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

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

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

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

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

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

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

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

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