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

History | View | Annotate | Download (107 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
import javax.json.JsonObject;
42

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

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

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

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

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

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

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

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

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

    
207
    private DefaultDataManager dataManager = null;
208

    
209
    private FeatureStoreProvider provider = null;
210

    
211
    private DefaultFeatureIndexes indexes;
212

    
213
    private DefaultFeatureStoreTransforms transforms;
214

    
215
    DelegatedDynObject metadata;
216

    
217
    private Set metadataChildren;
218

    
219
    private Long featureCount = null;
220

    
221
    private long temporalOid = 0;
222

    
223
    private FeatureCacheProvider cache;
224

    
225
    StateInformation state;
226

    
227
    FeatureStoreTimeSupport timeSupport;
228

    
229

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

    
232
        private static final long serialVersionUID = 4109026189635185666L;
233

    
234
        private boolean broken;
235
        private Throwable breakingsCause;
236

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

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

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

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

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

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

    
269

    
270

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

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

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

    
293
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
294

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

    
300
        this.dataManager = (DefaultDataManager) dataManager;
301

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

    
310
    }
311

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
592
        }
593

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

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

    
601
    }
602

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

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

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

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

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

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

    
714
                    }
715

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

    
721

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
915
    }
916

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

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

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

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

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

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

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

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

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

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

    
980
    }
981

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

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

    
991
    }
992

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

    
997
    }
998

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

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

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

    
1017
    }
1018

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

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

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

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

    
1049
    //
1050
    // ====================================================================
1051
    // Edicion
1052
    //
1053

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

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

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

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

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

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

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

    
1094
        }
1095

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

    
1100
        featureCount = null;
1101

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1305
    private static EditableFeature lastChangedFeature = null;
1306

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

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

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

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

    
1345
        waitForIndexes();
1346

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

    
1359

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1724
        case MODE_APPEND:
1725
                return true;
1726

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2252
        }
2253

    
2254
        return type;
2255
    }
2256

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

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

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

    
2300
            return avoidEditable(defaultFeatureType);
2301

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

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

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

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

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

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

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

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

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

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

    
2431
    }
2432

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

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

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

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

    
2469
    @Override
2470
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2471
        FeatureType ft = this.getDefaultFeatureType();
2472
        EditableFeature f = this.createNewFeature(ft, false);
2473
        f.copyFrom(defaultValues);
2474
        return f;
2475
    }
2476

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

    
2483
    @Override
2484
    public EditableFeatureType createFeatureType(String id) {
2485
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2486
        return ftype;
2487
    }
2488

    
2489
    //
2490
    // ====================================================================
2491
    // Index related methods
2492
    //
2493

    
2494
    @Override
2495
    public FeatureIndexes getIndexes() {
2496
        return this.indexes;
2497
    }
2498

    
2499
    @Override
2500
    public FeatureIndex createIndex(FeatureType featureType,
2501
        String attributeName, String indexName) throws DataException {
2502
        return createIndex(null, featureType, attributeName, indexName);
2503
    }
2504

    
2505
    @Override
2506
    public FeatureIndex createIndex(String indexTypeName,
2507
        FeatureType featureType, String attributeName, String indexName)
2508
        throws DataException {
2509

    
2510
        return createIndex(indexTypeName, featureType, attributeName,
2511
            indexName, false, null);
2512
    }
2513

    
2514
    @Override
2515
    public FeatureIndex createIndex(FeatureType featureType,
2516
        String attributeName, String indexName, Observer observer)
2517
        throws DataException {
2518
        return createIndex(null, featureType, attributeName, indexName,
2519
            observer);
2520
    }
2521

    
2522
    @Override
2523
    public FeatureIndex createIndex(String indexTypeName,
2524
        FeatureType featureType, String attributeName, String indexName,
2525
        final Observer observer) throws DataException {
2526

    
2527
        return createIndex(indexTypeName, featureType, attributeName,
2528
            indexName, true, observer);
2529
    }
2530

    
2531
    private FeatureIndex createIndex(String indexTypeName,
2532
        FeatureType featureType, String attributeName, String indexName,
2533
        boolean background, final Observer observer) throws DataException {
2534

    
2535
        checkNotInAppendMode();
2536
        FeatureIndexProviderServices index;
2537
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2538
                featureType, indexName,
2539
                featureType.getAttributeDescriptor(attributeName));
2540

    
2541
        try {
2542
            index.fill(background, observer);
2543
        } catch (FeatureIndexException e) {
2544
            throw new InitializeException(index.getName(), e);
2545
        }
2546

    
2547
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2548
        return index;
2549
    }
2550

    
2551
    //
2552
    // ====================================================================
2553
    // Transforms related methods
2554
    //
2555

    
2556
    @Override
2557
    public FeatureStoreTransforms getTransforms() {
2558
        return this.transforms;
2559
    }
2560

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

    
2624
    //
2625
    // ====================================================================
2626
    // UndoRedo related methods
2627
    //
2628

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

    
2634
    @Override
2635
    public boolean canUndo() {
2636
        return commands.canUndo();
2637
    }
2638

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

    
2646
    @Override
2647
    public void undo(int num) throws UndoException {
2648
        for (int i = 0; i < num; i++) {
2649
            undo();
2650
        }
2651
    }
2652

    
2653
    //
2654
    // ====================================================================
2655
    // Metadata related methods
2656
    //
2657

    
2658
    @Override
2659
    public Object getMetadataID() {
2660
        return this.provider.getSourceId();
2661
    }
2662

    
2663
    @Override
2664
    public void delegate(DynObject dynObject) {
2665
        this.metadata.delegate(dynObject);
2666
    }
2667

    
2668
    @Override
2669
    public DynClass getDynClass() {
2670
        return this.metadata.getDynClass();
2671
    }
2672

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

    
2700
    @Override
2701
    public boolean hasDynValue(String name) {
2702
        if (this.transforms.hasDynValue(name)) {
2703
            return true;
2704
        }
2705
        return this.metadata.hasDynValue(name);
2706
    }
2707

    
2708
    @Override
2709
    public boolean hasDynMethod(String name) {
2710
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2711
    }
2712

    
2713
    @Override
2714
    public void implement(DynClass dynClass) {
2715
        this.metadata.implement(dynClass);
2716
    }
2717

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

    
2724
    @Override
2725
    public Object invokeDynMethod(int code, Object[] args)
2726
        throws DynMethodException {
2727
        return this.metadata.invokeDynMethod(this, code, args);
2728
    }
2729

    
2730
    @Override
2731
    public void setDynValue(String name, Object value)
2732
        throws DynFieldNotFoundException {
2733
                if( this.transforms.hasDynValue(name) ) {
2734
                        this.transforms.setDynValue(name, value);
2735
                        return;
2736
                }
2737
        this.metadata.setDynValue(name, value);
2738

    
2739
    }
2740

    
2741
    /*
2742
     * (non-Javadoc)
2743
     *
2744
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2745
     */
2746
    @Override
2747
    public Set getMetadataChildren() {
2748
        return this.metadataChildren;
2749
    }
2750

    
2751
    /*
2752
     * (non-Javadoc)
2753
     *
2754
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2755
     */
2756
    @Override
2757
    public String getMetadataName() {
2758
        return this.provider.getProviderName();
2759
    }
2760

    
2761
    public FeatureTypeManager getFeatureTypeManager() {
2762
        return this.featureTypeManager;
2763
    }
2764

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

    
2786
    private Long getTemporalOID() {
2787
        return this.temporalOid++;
2788
    }
2789

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

    
2806
    @Override
2807
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2808
        return ((DefaultFeature) feature).getData();
2809
    }
2810

    
2811
    @Override
2812
    public DataStore getStore() {
2813
        return this;
2814
    }
2815

    
2816
    @Override
2817
    public FeatureStore getFeatureStore() {
2818
        return this;
2819
    }
2820

    
2821
    @Override
2822
    public void createCache(String name, DynObject parameters)
2823
        throws DataException {
2824
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2825
        if (cache == null) {
2826
            throw new CreateException("FeaureCacheProvider", null);
2827
        }
2828
        cache.apply(this, provider);
2829
        provider = cache;
2830

    
2831
        featureCount = null;
2832
    }
2833

    
2834
    @Override
2835
    public FeatureCache getCache() {
2836
        return cache;
2837
    }
2838

    
2839
    @Override
2840
    public void clear() {
2841
        if (metadata != null) {
2842
            metadata.clear();
2843
        }
2844
    }
2845

    
2846
    @Override
2847
    public String getName() {
2848
        if( this.provider != null ) {
2849
            return this.provider.getName();
2850
        }
2851
        if( this.parameters instanceof HasAFile ) {
2852
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
2853
        }
2854
        return "unknow";
2855
    }
2856

    
2857
    @Override
2858
    public String getFullName() {
2859
        try {
2860
            if( this.provider!=null ) {
2861
                return this.provider.getFullName();
2862
            }
2863
            if( this.parameters instanceof HasAFile ) {
2864
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
2865
            }
2866
            return null;
2867
        } catch(Throwable th) {
2868
            return null;
2869
        }
2870
    }
2871

    
2872
    @Override
2873
    public String getProviderName() {
2874
        if( this.provider!=null ) {
2875
            return this.provider.getProviderName();
2876
        }
2877
        if( this.parameters != null ) {
2878
            return this.parameters.getDataStoreName();
2879
        }
2880
        return null;
2881

    
2882
    }
2883

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

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

    
2894
    @Override
2895
    public int getRetrievedFeaturesLimit() {
2896
        return this.provider.getRetrievedFeaturesLimit();
2897
    }
2898

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

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

    
2926
    @Override
2927
    public Collection getTimes(Interval interval) {
2928
        if( this.timeSupport!=null ) {
2929
            return this.timeSupport.getTimes(interval);
2930
        }
2931
        return this.provider.getTimes(interval);
2932
    }
2933

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

    
2966
    @Override
2967
    @SuppressWarnings("CloneDoesntCallSuperClone")
2968
    public Object clone() throws CloneNotSupportedException {
2969

    
2970
        DataStoreParameters dsp = getParameters();
2971

    
2972
        DefaultFeatureStore cloned_store = null;
2973

    
2974
        try {
2975
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2976
                openStore(this.getProviderName(), dsp);
2977
            if (transforms != null) {
2978
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2979
                cloned_store.transforms.setStoreForClone(cloned_store);
2980
            }
2981
        } catch (Exception e) {
2982
            throw new CloneException(e);
2983
        }
2984
        return cloned_store;
2985

    
2986
    }
2987

    
2988
    @Override
2989
    public Feature getFeature(DynObject dynobject) {
2990
        if (dynobject instanceof DynObjectFeatureFacade){
2991
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2992
            return f;
2993
        }
2994
        return null;
2995
    }
2996

    
2997
    @Override
2998
    public Iterator iterator() {
2999
        try {
3000
            return this.getFeatureSet().fastIterator();
3001
        } catch (DataException ex) {
3002
            throw new RuntimeException(ex);
3003
        }
3004
    }
3005

    
3006
    @Override
3007
    public ExpressionBuilder createExpressionBuilder() {
3008
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3009
        return builder;
3010
    }
3011

    
3012
    @Override
3013
    public ExpressionBuilder createExpression() {
3014
        return createExpressionBuilder();
3015
    }
3016

    
3017
    public FeatureSet features() throws DataException {
3018
        // This is to avoid jython to create a property with this name
3019
        // to access method getFeatures.
3020
        return this.getFeatureSet();
3021
    }
3022

    
3023
    @Override
3024
    public DataStoreProviderFactory getProviderFactory() {
3025
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3026
        return factory;
3027
    }
3028

    
3029
    @Override
3030
    public void useCache(String providerName, DynObject parameters) throws DataException {
3031
        throw new UnsupportedOperationException();
3032
    }
3033

    
3034
    @Override
3035
    public boolean isBroken() {
3036
        return this.state.isBroken();
3037
    }
3038

    
3039
    @Override
3040
    public Throwable getBreakingsCause() {
3041
            return this.state.getBreakingsCause();
3042
    }
3043

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

    
3054
    @Override
3055
    public FeatureReference getFeatureReference(String code) {
3056
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
3057
        return featureReference;
3058
    }
3059

    
3060
    @Override
3061
    public long getPendingChangesCount() {
3062
        if( this.featureManager==null ) {
3063
            return 0;
3064
        }
3065
        return this.featureManager.getPendingChangesCount();
3066
    }
3067

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

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

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

    
3123
    @Override
3124
    public boolean supportReferences() {
3125
        try {
3126
            return this.getDefaultFeatureType().supportReferences();
3127
        } catch (Exception ex) {
3128
            return false;
3129
        }
3130
    }
3131

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