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

History | View | Annotate | Download (106 KB)

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

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

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

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

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

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

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

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

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

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

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

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

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

    
206
    private DefaultDataManager dataManager = null;
207

    
208
    private FeatureStoreProvider provider = null;
209

    
210
    private DefaultFeatureIndexes indexes;
211

    
212
    private DefaultFeatureStoreTransforms transforms;
213

    
214
    DelegatedDynObject metadata;
215

    
216
    private Set metadataChildren;
217

    
218
    private Long featureCount = null;
219

    
220
    private long temporalOid = 0;
221

    
222
    private FeatureCacheProvider cache;
223

    
224
    StateInformation state;
225

    
226
    FeatureStoreTimeSupport timeSupport;
227

    
228

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

    
231
        private static final long serialVersionUID = 4109026189635185666L;
232

    
233
        private boolean broken;
234
        private Throwable breakingsCause;
235

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

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

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

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

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

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

    
268

    
269

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

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

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

    
292
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
293

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

    
299
        this.dataManager = (DefaultDataManager) dataManager;
300

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

    
309
    }
310

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
591
        }
592

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

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

    
600
    }
601

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

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

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

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

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

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

    
713
                    }
714

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

    
720

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
914
    }
915

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

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

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

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

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

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

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

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

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

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

    
979
    }
980

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

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

    
990
    }
991

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

    
996
    }
997

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

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

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

    
1016
    }
1017

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

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

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

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

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

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

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

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

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

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

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

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

    
1093
        }
1094

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

    
1099
        featureCount = null;
1100

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

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

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

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

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

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

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

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

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

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

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

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

    
1230
    @Override
1231
    synchronized public void update(EditableFeatureType type)
1232
        throws DataException {
1233
        try {
1234
            if (type == null) {
1235
                throw new NullFeatureTypeException(getName());
1236
            }
1237
            boolean typehasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1238
            if (typehasStrongChanges) {
1239
                checkInEditingMode();
1240
            }  else if(this.isAppending()) {
1241
                throw new NeedEditingModeException(this.getName());
1242
            }
1243
            // FIXME: Comprobar que es un featureType aceptable.
1244
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
1245
            newVersionOfUpdate();
1246
            
1247
            FeatureType oldt = type.getSource().getCopy();
1248
            FeatureType newt = type.getCopy();
1249
            commands.update(newt, oldt);
1250
            if (typehasStrongChanges) { 
1251
                hasStrongChanges = true;
1252
            }
1253
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1254
        } catch (Exception e) {
1255
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1256
        }
1257
    }
1258

    
1259
    @Override
1260
    public void delete(Feature feature) throws DataException {
1261
        this.commands.delete(feature);
1262
    }
1263

    
1264
    synchronized public void doDelete(Feature feature) throws DataException {
1265
        try {
1266
            checkInEditingMode();
1267
            checkIsOwnFeature(feature);
1268
            if (feature instanceof EditableFeature) {
1269
                throw new StoreDeleteEditableFeatureException(getName());
1270
            }
1271
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1272

    
1273
            //Update the featureManager and the spatialManager
1274
            featureManager.delete(feature.getReference());
1275
            spatialManager.deleteFeature(feature);
1276

    
1277
            newVersionOfUpdate();
1278
            hasStrongChanges = true;
1279
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1280
        } catch (Exception e) {
1281
            throw new StoreDeleteFeatureException(e, this.getName());
1282
        }
1283
    }
1284

    
1285
    private static EditableFeature lastChangedFeature = null;
1286

    
1287
    @Override
1288
    public synchronized void insert(EditableFeature feature)
1289
        throws DataException {
1290
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1291
        try {
1292
            switch (mode) {
1293
            case MODE_QUERY:
1294
                throw new NeedEditingModeException(this.getName());
1295

    
1296
            case MODE_APPEND:
1297
                checkIsOwnFeature(feature);
1298
                if (feature.getSource() != null) {
1299
                    throw new NoNewFeatureInsertException(this.getName());
1300
                }
1301
                this.featureCount = null;
1302
                notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1303
                feature.validate(Feature.UPDATE);
1304
                provider.append(((DefaultEditableFeature) feature).getData());
1305
                hasStrongChanges = true;
1306
                hasInserts = true;
1307
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1308
                break;
1309

    
1310
            case MODE_FULLEDIT:
1311
                if (feature.getSource() != null) {
1312
                    throw new NoNewFeatureInsertException(this.getName());
1313
                }
1314
                commands.insert(feature);
1315
            }
1316
        } catch (Exception e) {
1317
            throw new StoreInsertFeatureException(e, this.getName());
1318
        }
1319
    }
1320

    
1321
    synchronized public void doInsert(EditableFeature feature)
1322
        throws DataException {
1323
        checkIsOwnFeature(feature);
1324

    
1325
        waitForIndexes();
1326

    
1327
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1328
        newVersionOfUpdate();
1329
        if ((lastChangedFeature == null)
1330
            || (lastChangedFeature.getSource() != feature.getSource())) {
1331
            lastChangedFeature = feature;
1332
            feature.validate(Feature.UPDATE);
1333
            lastChangedFeature = null;
1334
        }
1335
        //Update the featureManager and the spatialManager
1336
        ((DefaultEditableFeature) feature).setInserted(true);
1337
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1338

    
1339

    
1340
        featureManager.add(newFeature);
1341
        spatialManager.insertFeature(newFeature);
1342

    
1343
        hasStrongChanges = true;
1344
        hasInserts = true;
1345
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1346
    }
1347

    
1348
    @Override
1349
    public void update(EditableFeature feature)
1350
    throws DataException {
1351
        if ((feature).getSource() == null) {
1352
            insert(feature);
1353
            return;
1354
        }
1355
        commands.update(feature, feature.getSource());
1356
    }
1357

    
1358
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1359
        throws DataException {
1360
        try {
1361
            checkInEditingMode();
1362
            checkIsOwnFeature(feature);
1363
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature);
1364
            newVersionOfUpdate();
1365
            if ((lastChangedFeature == null)
1366
                || (lastChangedFeature.getSource() != feature.getSource())) {
1367
                lastChangedFeature = feature;
1368
                feature.validate(Feature.UPDATE);
1369
                lastChangedFeature = null;
1370
            }
1371

    
1372
            //Update the featureManager and the spatialManager
1373
            Feature newf = feature.getNotEditableCopy();
1374
            featureManager.update(newf, oldFeature);
1375
            spatialManager.updateFeature(newf, oldFeature);
1376

    
1377
            hasStrongChanges = true;
1378
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1379
        } catch (Exception e) {
1380
            throw new StoreUpdateFeatureException(e, this.getName());
1381
        }
1382
    }
1383

    
1384
    @Override
1385
    synchronized public void redo() throws RedoException {
1386
        Command redo = commands.getNextRedoCommand();
1387
        try {
1388
            checkInEditingMode();
1389
        } catch (NeedEditingModeException ex) {
1390
            throw new RedoException(redo, ex);
1391
        }
1392
        notifyChange(FeatureStoreNotification.BEFORE_REDO, redo);
1393
        newVersionOfUpdate();
1394
        commands.redo();
1395
        hasStrongChanges = true;
1396
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1397
    }
1398

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

    
1414
    @Override
1415
    public List getRedoInfos() {
1416
        if (isEditing() && (commands != null)) {
1417
            return commands.getRedoInfos();
1418
        } else {
1419
            return null;
1420
        }
1421
    }
1422

    
1423
    @Override
1424
    public List getUndoInfos() {
1425
        if (isEditing() && (commands != null)) {
1426
            return commands.getUndoInfos();
1427
        } else {
1428
            return null;
1429
        }
1430
    }
1431

    
1432
    public synchronized FeatureCommandsStack getCommandsStack()
1433
        throws DataException {
1434
        checkInEditingMode();
1435
        return commands;
1436
    }
1437

    
1438
    @Override
1439
    synchronized public void cancelEditing() throws DataException {
1440
        if( spatialManager!=null ) {
1441
            spatialManager.cancelModifies();
1442
        }
1443
        try {
1444
            switch (mode) {
1445
            case MODE_QUERY:
1446
                throw new NeedEditingModeException(this.getName());
1447

    
1448
            case MODE_APPEND:
1449
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1450
                provider.abortAppend();
1451
                exitEditingMode();
1452
                ((FeatureSelection) this.getSelection()).deselectAll();
1453
                updateIndexes();
1454
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1455

    
1456
            case MODE_FULLEDIT:
1457
                boolean clearSelection = this.hasStrongChanges;
1458
                if (this.selection instanceof FeatureReferenceSelection) {
1459
                    clearSelection = this.hasInserts;
1460
                }
1461
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1462
                exitEditingMode();
1463
                if (clearSelection) {
1464
                    ((FeatureSelection) this.getSelection()).deselectAll();
1465
                }
1466
                updateIndexes();
1467
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1468
            }
1469
        } catch (Exception e) {
1470
            throw new StoreCancelEditingException(e, this.getName());
1471
        }
1472
    }
1473

    
1474
    @Override
1475
    synchronized public void finishEditing() throws DataException {
1476
        LOGGER.debug("finish editing of mode: {}", mode);
1477
        try {
1478

    
1479
            /*
1480
             * Selection needs to be cleared when editing stops
1481
             * to prevent conflicts with selection remaining from
1482
             * editing mode.
1483
             */
1484
//            ((FeatureSelection) this.getSelection()).deselectAll();
1485
            Map<String,List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1486
            switch (mode) {
1487
            case MODE_QUERY:
1488
                throw new NeedEditingModeException(this.getName());
1489

    
1490
            case MODE_APPEND:
1491
                if( selection!=null ) {
1492
                    selection = null;
1493
                }
1494
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1495
                saveDALFile();
1496
                provider.endAppend();
1497
                exitEditingMode();
1498
                this.updateComputedFields(computedFields);
1499
                loadDALFile();
1500
                updateIndexes();
1501
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1502
                break;
1503

    
1504
            case MODE_FULLEDIT:
1505
                if (hasStrongChanges && !this.allowWrite()) {
1506
                    throw new WriteNotAllowedException(getName());
1507
                }
1508
                saveDALFile();
1509
                if(featureManager.isSelectionCompromised() && selection!=null ) {
1510
                    selection = null;
1511
                }
1512
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1513
                if (hasStrongChanges) {
1514
                    validateFeatures(Feature.FINISH_EDITING);
1515

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

    
1563
        List<FeatureType> theTypes = new ArrayList<>();
1564
        theTypes.addAll(this.getFeatureTypes());
1565
        theTypes.add(this.getDefaultFeatureType());
1566
        for( int n=0; n<theTypes.size(); n++ ) {
1567
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1568
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1569
            if(x!=null && !x.isEmpty()) {
1570
                for (FeatureAttributeDescriptor attrdesc : x) {
1571
                    if (type.get(attrdesc.getName())==null) {
1572
                        type.add(attrdesc);
1573
                    }
1574
                }
1575
            }
1576
        }
1577
        
1578
    }
1579
    private List<FeatureStoreProvider.FeatureTypeChanged> removeCalculatedAttributes(List<FeatureStoreProvider.FeatureTypeChanged> ftypes) {
1580
        // FIXME: Falta por implementar
1581
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
1582
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
1583
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
1584
//                if (attributeDescriptor.isComputed()) {
1585
//                    target.remove(attributeDescriptor.getName());
1586
//                }
1587
//            }
1588
//        }
1589
        return ftypes;
1590
    }
1591
    
1592

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

    
1657
        case MODE_APPEND:
1658
          this.provider.endAppend();
1659
          exitEditingMode();
1660
          invalidateIndexes();
1661
          this.provider.beginAppend();
1662
          hasInserts = false;
1663
          break;
1664

    
1665
        case MODE_FULLEDIT:
1666
          if (hasStrongChanges && !this.allowWrite()) {
1667
            throw new WriteNotAllowedException(getName());
1668
          }
1669
          if (hasStrongChanges) {
1670
            validateFeatures(Feature.FINISH_EDITING);
1671
            provider.performChanges(featureManager.getDeleted(),
1672
              featureManager.getInserted(),
1673
              featureManager.getUpdated(),
1674
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1675
          }
1676
          invalidateIndexes();
1677
          featureManager = new FeatureManager();
1678
          featureTypeManager = new FeatureTypeManager(this);
1679
          spatialManager = new SpatialManager(this, provider.getEnvelope());
1680

    
1681
          commands =
1682
            new DefaultFeatureCommandsStack(this, featureManager,
1683
              spatialManager, featureTypeManager);
1684
          featureCount = null;
1685
          hasStrongChanges = false;
1686
          hasInserts = false;
1687
          break;
1688
        }
1689
      } catch (Exception e) {
1690
        throw new FinishEditingException(e);
1691
      }
1692
    }
1693

    
1694
    @Override
1695
    synchronized public boolean canCommitChanges() throws DataException {
1696
        if ( !this.allowWrite()) {
1697
                return false;
1698
        }
1699
            switch (mode) {
1700
            default:
1701
        case MODE_QUERY:
1702
                return false;
1703

    
1704
        case MODE_APPEND:
1705
                return true;
1706

    
1707
        case MODE_FULLEDIT:
1708
            List types = this.getFeatureTypes();
1709
            for( int i=0; i<types.size(); i++ ) {
1710
                    Object type = types.get(i);
1711
                    if( type instanceof DefaultEditableFeatureType ) {
1712
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1713
                                    return false;
1714
                            }
1715
                    }
1716
            }
1717
            return true;
1718
            }
1719
    }
1720

    
1721
    @Override
1722
    public void beginEditingGroup(String description)
1723
        throws NeedEditingModeException {
1724
        checkInEditingMode();
1725
        commands.startComplex(description);
1726
    }
1727

    
1728
    @Override
1729
    public void endEditingGroup() throws NeedEditingModeException {
1730
        checkInEditingMode();
1731
        commands.endComplex();
1732
    }
1733

    
1734
    @Override
1735
    public boolean isAppendModeSupported() {
1736
        return this.provider.supportsAppendMode();
1737
    }
1738

    
1739
    @Override
1740
    public void export(DataServerExplorer explorer, String provider,
1741
        NewFeatureStoreParameters params) throws DataException {
1742

    
1743
        if (this.getFeatureTypes().size() != 1) {
1744
            throw new NotYetImplemented(
1745
                "export whith more than one type not yet implemented");
1746
        }
1747
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1748
        FeatureStore target = null;
1749
        FeatureSet features = null;
1750
        DisposableIterator iterator = null;
1751
        try {
1752
            FeatureType type = this.getDefaultFeatureType();
1753
            if ((params.getDefaultFeatureType() == null)
1754
                || (params.getDefaultFeatureType().size() == 0)) {
1755
                params.setDefaultFeatureType(type.getEditable());
1756

    
1757
            }
1758
            explorer.add(provider, params, true);
1759

    
1760
            DataManager manager = DALLocator.getDataManager();
1761
            target = (FeatureStore) manager.openStore(provider, params);
1762
            FeatureType targetType = target.getDefaultFeatureType();
1763

    
1764
            target.edit(MODE_APPEND);
1765
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
1766
            if (featureSelection.getSize() > 0) {
1767
                features = this.getFeatureSelection();
1768
            } else {
1769
                if ((pkattrs != null) && (pkattrs.length > 0)) {
1770
                    FeatureQuery query = createFeatureQuery();
1771
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
1772
                        query.getOrder().add(pkattr.getName(), true);
1773
                    }
1774
                    features = this.getFeatureSet(query);
1775
                } else {
1776
                    features = this.getFeatureSet();
1777
                }
1778
            }
1779
            iterator = features.fastIterator();
1780
            while (iterator.hasNext()) {
1781
                DefaultFeature feature = (DefaultFeature) iterator.next();
1782
                target.insert(target.createNewFeature(targetType, feature));
1783
            }
1784
            target.finishEditing();
1785
            target.dispose();
1786
        } catch (Exception e) {
1787
            throw new DataExportException(e, params.toString());
1788
        } finally {
1789
            dispose(iterator);
1790
            dispose(features);
1791
            dispose(target);
1792
        }
1793
    }
1794

    
1795
    public void copyTo(final FeatureStore target) {
1796
        boolean finishEditingAtEnd = false;
1797
        try {
1798
            if( !target.isEditing() && !target.isAppending() ) {
1799
                finishEditingAtEnd = true;
1800
                target.edit(MODE_APPEND);
1801
            }
1802
            this.accept(new Visitor() {
1803
                @Override
1804
                public void visit(Object obj) throws VisitCanceledException, BaseException {
1805
                    Feature f_src = (Feature) obj;
1806
                    EditableFeature f_dst = target.createNewFeature(f_src);
1807
                    target.insert(f_dst);
1808
                }
1809
            });
1810
            if( finishEditingAtEnd ) {
1811
                target.finishEditing();
1812
            }
1813
            
1814
        } catch(Exception ex) {
1815
            try {
1816
                if( finishEditingAtEnd ) {
1817
                    target.cancelEditing();
1818
                }
1819
            } catch (Exception ex1) {
1820
            }
1821
            throw new RuntimeException("Can't copy store.",ex);
1822
        }
1823
            
1824
    }
1825
    
1826
    //
1827
    // ====================================================================
1828
    // Obtencion de datos
1829
    // getDataCollection, getFeatureCollection
1830
    //
1831

    
1832
    @Override
1833
    public DataSet getDataSet() throws DataException {
1834
        checkNotInAppendMode();
1835
        FeatureQuery query =
1836
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1837
        return new DefaultFeatureSet(this, query);
1838
    }
1839

    
1840
    @Override
1841
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1842
        checkNotInAppendMode();
1843
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1844
    }
1845

    
1846
    @Override
1847
    public void getDataSet(Observer observer) throws DataException {
1848
        checkNotInAppendMode();
1849
        this.getFeatureSet(null, observer);
1850
    }
1851

    
1852
    @Override
1853
    public void getDataSet(DataQuery dataQuery, Observer observer)
1854
        throws DataException {
1855
        checkNotInAppendMode();
1856
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1857
    }
1858

    
1859
    @Override
1860
    public FeatureSet getFeatureSet() throws DataException {
1861
        return this.getFeatureSet((FeatureQuery)null);
1862
    }
1863

    
1864
    @Override
1865
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1866
        throws DataException {
1867
        checkNotInAppendMode();
1868
        if( featureQuery==null ) {
1869
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1870
        }
1871
        return new DefaultFeatureSet(this, featureQuery);
1872
    }
1873

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

    
1879
    @Override
1880
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
1881
        return this.getFeatureSet(filter, sortBy, true);
1882
    }
1883

    
1884
    @Override
1885
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
1886
        return this.getFeatureSet(filter, null, true);
1887
    }
1888
    
1889
    @Override
1890
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
1891
        return this.getFeatureSet(filter, sortBy, true);
1892
    }
1893

    
1894
    @Override
1895
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
1896
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1897
        return this.getFeatureSet(query);
1898
    }
1899
    
1900
    @Override
1901
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
1902
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1903
        return this.getFeatureSet(query);
1904
    }
1905
    
1906
    @Override
1907
    public List<Feature> getFeatures(String filter)  {
1908
        return this.getFeatures(filter, null, true);
1909
    }
1910

    
1911
    @Override
1912
    public List<Feature> getFeatures(String filter, String sortBy)  {
1913
        return this.getFeatures(filter, sortBy, true);
1914
    }
1915

    
1916
    @Override
1917
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
1918
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1919
        return this.getFeatures(query, 0);
1920
    }
1921
    
1922
    @Override
1923
    public List<Feature> getFeatures(Expression filter)  {
1924
        return this.getFeatures(filter, null, true);
1925
    }
1926

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

    
1932
    @Override
1933
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
1934
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1935
        return this.getFeatures(query, 0);
1936
    }
1937
    
1938
    @Override
1939
    public List<Feature> getFeatures(FeatureQuery query)  {
1940
        return this.getFeatures(query, 0);
1941
    }
1942
    
1943
    @Override
1944
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
1945
        try {
1946
            if( pageSize<=0 ) {
1947
                pageSize = 100;
1948
            }
1949
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
1950
            return pager.asList();
1951
        } catch (BaseException ex) {
1952
            throw new RuntimeException("Can't create the list of features.", ex);
1953
        }
1954
    }
1955

    
1956
    @Override
1957
    public List<Feature> getFeatures() {
1958
        return this.getFeatures(null, 0);
1959
    }
1960

    
1961
    @Override
1962
    public Feature first() throws DataException {
1963
        return this.findFirst((FeatureQuery)null);
1964
    }
1965
    
1966
    @Override
1967
    public Feature findFirst(String filter) throws DataException {
1968
        return this.findFirst(filter, null, true);
1969
    }
1970

    
1971
    @Override
1972
    public Feature findFirst(String filter, String sortBy) throws DataException {
1973
        return this.findFirst(filter, sortBy, true);
1974
    }
1975

    
1976
    @Override
1977
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
1978
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1979
        return findFirst(query);
1980
    }
1981
    
1982
    @Override
1983
    public Feature findFirst(Expression filter) throws DataException {
1984
        return this.findFirst(filter, null, true);
1985
    }
1986

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

    
1992
    @Override
1993
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
1994
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1995
        return findFirst(query);
1996
    }
1997
    
1998
    @Override
1999
    public Feature findFirst(FeatureQuery query) throws DataException {
2000
        if( query == null ) {
2001
            query = this.createFeatureQuery();
2002
        } else {
2003
            query = query.getCopy();
2004
        }
2005
        query.setLimit(1);
2006
        final MutableObject<Feature> feature = new MutableObject<>();
2007
        try {
2008
            this.accept(new Visitor() {
2009
                @Override
2010
                public void visit(Object obj) throws VisitCanceledException, BaseException {
2011
                    feature.setValue((Feature) obj);
2012
                    throw new VisitCanceledException();
2013
                }
2014
            }, query);
2015
        } catch(VisitCanceledException ex) {
2016

    
2017
        } catch(DataException ex) {
2018
            throw ex;
2019
        } catch(Exception ex) {
2020
            throw new RuntimeException("", ex);
2021
        }
2022
        return feature.getValue();
2023
    }
2024

    
2025
    @Override
2026
    public void accept(Visitor visitor) throws BaseException {
2027
        this.accept(visitor, null);
2028
    }
2029

    
2030
    @Override
2031
    public void accept(Visitor visitor, DataQuery dataQuery)
2032
        throws BaseException {
2033
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2034
        try {
2035
            set.accept(visitor);
2036
        } finally {
2037
            set.dispose();
2038
        }
2039
    }
2040

    
2041
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2042
        throws DataException {
2043
        DefaultFeatureType fType =
2044
            (DefaultFeatureType) this.getFeatureType(featureQuery
2045
                .getFeatureTypeId());
2046
        if( featureQuery.hasAttributeNames() || 
2047
            featureQuery.hasConstantsAttributeNames() ||
2048
            fType.hasRequiredFields()    
2049
            ) {
2050
            if( featureQuery.isGrouped() ) {
2051
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2052
            } else {
2053
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2054
            }
2055
        }
2056
        return fType;
2057
    }
2058

    
2059
    @Override
2060
    public void getFeatureSet(Observer observer) throws DataException {
2061
        checkNotInAppendMode();
2062
        this.getFeatureSet(null, observer);
2063
    }
2064

    
2065
    @Override
2066
    public void getFeatureSet(FeatureQuery query, Observer observer)
2067
        throws DataException {
2068
        class LoadInBackGround implements Runnable {
2069

    
2070
            private final FeatureStore store;
2071
            private final FeatureQuery query;
2072
            private final Observer observer;
2073

    
2074
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2075
                Observer observer) {
2076
                this.store = store;
2077
                this.query = query;
2078
                this.observer = observer;
2079
            }
2080

    
2081
            void notify(FeatureStoreNotification theNotification) {
2082
                observer.update(store, theNotification);
2083
            }
2084

    
2085
            @Override
2086
            public void run() {
2087
                FeatureSet set = null;
2088
                try {
2089
                    set = store.getFeatureSet(query);
2090
                    notify(new DefaultFeatureStoreNotification(store,
2091
                        FeatureStoreNotification.LOAD_FINISHED, set));
2092
                } catch (Exception e) {
2093
                    notify(new DefaultFeatureStoreNotification(store,
2094
                        FeatureStoreNotification.LOAD_FINISHED, e));
2095
                } finally {
2096
                    dispose(set);
2097
                }
2098
            }
2099
        }
2100

    
2101
        checkNotInAppendMode();
2102
        if (query == null) {
2103
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2104
        }
2105
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2106
        Thread thread = new Thread(task, "Load Feature Set in background");
2107
        thread.start();
2108
    }
2109

    
2110
    @Override
2111
    public Feature getFeatureByReference(FeatureReference reference)
2112
        throws DataException {
2113
        checkNotInAppendMode();
2114
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
2115
        FeatureType featureType;
2116
        if (ref.getFeatureTypeId() == null) {
2117
            featureType = this.getDefaultFeatureType();
2118
        } else {
2119
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2120
        }
2121
        return this.getFeatureByReference(reference, featureType);
2122
    }
2123

    
2124
    @Override
2125
    public Feature getFeatureByReference(FeatureReference reference,
2126
        FeatureType featureType) throws DataException {
2127
        checkNotInAppendMode();
2128
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2129
        if (this.mode == MODE_FULLEDIT) {
2130
            Feature f = featureManager.get(reference, this, featureType);
2131
            if (f != null) {
2132
                return f;
2133
            }
2134
        }
2135

    
2136
        FeatureType sourceFeatureType = featureType;
2137
        if (!this.transforms.isEmpty()) {
2138
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2139
        }
2140
        // TODO comprobar que el id es de este store
2141

    
2142
        DefaultFeature feature =
2143
            new DefaultFeature(this,
2144
                this.provider.getFeatureProviderByReference(
2145
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2146

    
2147
        if (!this.transforms.isEmpty()) {
2148
            return this.transforms.applyTransform(feature, featureType);
2149
        }
2150
        return feature;
2151
    }
2152

    
2153
    //
2154
    // ====================================================================
2155
    // Gestion de features
2156
    //
2157

    
2158
    private FeatureType fixFeatureType(DefaultFeatureType type)
2159
        throws DataException {
2160
        FeatureType original = this.getDefaultFeatureType();
2161

    
2162
        if ((type == null) || type.equals(original)) {
2163
            return original;
2164
        } else {
2165
            if (!type.isSubtypeOf(original)) {
2166
                Iterator iter = this.getFeatureTypes().iterator();
2167
                FeatureType tmpType;
2168
                boolean found = false;
2169
                while (iter.hasNext()) {
2170
                    tmpType = (FeatureType) iter.next();
2171
                    if (type.equals(tmpType)) {
2172
                        return type;
2173

    
2174
                    } else
2175
                        if (type.isSubtypeOf(tmpType)) {
2176
                            found = true;
2177
                            original = tmpType;
2178
                            break;
2179
                        }
2180

    
2181
                }
2182
                if (!found) {
2183
                    throw new IllegalFeatureTypeException(getName());
2184
                }
2185
            }
2186
        }
2187

    
2188
        // Checks that type has all fields of pk
2189
        // else add the missing attributes at the end.
2190
        if (!original.hasOID()) {
2191
            // Gets original pk attributes
2192
            DefaultEditableFeatureType edOriginal =
2193
                (DefaultEditableFeatureType) original.getEditable();
2194
            FeatureAttributeDescriptor orgAttr;
2195
            Iterator edOriginalIter = edOriginal.iterator();
2196
            while (edOriginalIter.hasNext()) {
2197
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2198
                if (!orgAttr.isPrimaryKey()) {
2199
                    edOriginalIter.remove();
2200
                }
2201
            }
2202

    
2203
            // Checks if all pk attributes are in type
2204
            Iterator typeIterator;
2205
            edOriginalIter = edOriginal.iterator();
2206
            FeatureAttributeDescriptor attr;
2207
            while (edOriginalIter.hasNext()) {
2208
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2209
                typeIterator = type.iterator();
2210
                while (typeIterator.hasNext()) {
2211
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2212
                    if (attr.getName().equals(orgAttr.getName())) {
2213
                        edOriginalIter.remove();
2214
                        break;
2215
                    }
2216
                }
2217
            }
2218

    
2219
            // add missing pk attributes if any
2220
            if (edOriginal.size() > 0) {
2221
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2222
                DefaultEditableFeatureType edType =
2223
                    (DefaultEditableFeatureType) original.getEditable();
2224
                edType.clear();
2225
                edType.addAll(type);
2226
                edType.addAll(edOriginal);
2227
                if (!isEditable) {
2228
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2229
                }
2230
            }
2231

    
2232
        }
2233

    
2234
        return type;
2235
    }
2236

    
2237
    @Override
2238
    public void validateFeatures(int mode) throws DataException {
2239
        FeatureSet collection = null;
2240
        DisposableIterator iter = null;
2241
        try {
2242
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2243
            if( rules==null || rules.isEmpty() ) {
2244
                return;
2245
            }
2246
            checkNotInAppendMode();
2247
            collection = this.getFeatureSet();
2248
            iter = collection.fastIterator();
2249
            long previousVersionOfUpdate = currentVersionOfUpdate();
2250
            while (iter.hasNext()) {
2251
                ((DefaultFeature) iter.next()).validate(mode);
2252
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2253
                    throw new ConcurrentDataModificationException(getName());
2254
                }
2255
            }
2256
        } catch (Exception e) {
2257
            throw new ValidateFeaturesException(e, getName());
2258
        } finally {
2259
            DisposeUtils.disposeQuietly(iter);
2260
            DisposeUtils.disposeQuietly(collection);
2261
        }
2262
    }
2263

    
2264
    @Override
2265
    public FeatureType getDefaultFeatureType() throws DataException {
2266
        try {
2267

    
2268
            if (isEditing()) {
2269
                FeatureType auxFeatureType =
2270
                    featureTypeManager.getType(defaultFeatureType.getId());
2271
                if (auxFeatureType != null) {
2272
                    return avoidEditable(auxFeatureType);
2273
                }
2274
            }
2275
            FeatureType type = this.transforms.getDefaultFeatureType();
2276
                if (type != null) {
2277
                return avoidEditable(type);
2278
                }
2279

    
2280
            return avoidEditable(defaultFeatureType);
2281

    
2282
        } catch (Exception e) {
2283
            throw new GetFeatureTypeException(e, getName());
2284
        }
2285
    }
2286
    
2287
    private FeatureType avoidEditable(FeatureType ft) {
2288
        if (ft instanceof EditableFeatureType) {
2289
            return ((EditableFeatureType) ft).getNotEditableCopy();
2290
        } else {
2291
            return ft;
2292
        }
2293
    }
2294

    
2295
    @Override
2296
    public FeatureType getFeatureType(String featureTypeId)
2297
        throws DataException {
2298
        if (featureTypeId == null) {
2299
            return this.getDefaultFeatureType();
2300
        }
2301
        try {
2302
            if (isEditing()) {
2303
                FeatureType auxFeatureType =
2304
                    featureTypeManager.getType(featureTypeId);
2305
                if (auxFeatureType != null) {
2306
                    return auxFeatureType;
2307
                }
2308
            }
2309
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2310
            if (type != null) {
2311
                return type;
2312
            }
2313
            Iterator iter = this.featureTypes.iterator();
2314
            while (iter.hasNext()) {
2315
                type = (FeatureType) iter.next();
2316
                if (type.getId().equals(featureTypeId)) {
2317
                    return type;
2318
                }
2319
            }
2320
            return null;
2321
        } catch (Exception e) {
2322
            throw new GetFeatureTypeException(e, getName());
2323
        }
2324
    }
2325

    
2326
    public FeatureType getProviderDefaultFeatureType() {
2327
        return defaultFeatureType;
2328
    }
2329

    
2330
    @Override
2331
    public List getFeatureTypes() throws DataException {
2332
        try {
2333
            List types;
2334
            if (isEditing()) {
2335
                types = new ArrayList();
2336
                Iterator it = featureTypes.iterator();
2337
                while (it.hasNext()) {
2338
                    FeatureType type = (FeatureType) it.next();
2339
                    FeatureType typeaux =
2340
                        featureTypeManager.getType(type.getId());
2341
                    if (typeaux != null) {
2342
                        types.add(typeaux);
2343
                    } else {
2344
                        types.add(type);
2345
                    }
2346
                }
2347
                it = featureTypeManager.newsIterator();
2348
                while (it.hasNext()) {
2349
                    FeatureType type = (FeatureType) it.next();
2350
                    types.add(type);
2351
                }
2352
            } else {
2353
                types = this.transforms.getFeatureTypes();
2354
                if (types == null) {
2355
                    types = featureTypes;
2356
                }
2357
            }
2358
            return Collections.unmodifiableList(types);
2359
        } catch (Exception e) {
2360
            throw new GetFeatureTypeException(e, getName());
2361
        }
2362
    }
2363

    
2364
    public List getProviderFeatureTypes() throws DataException {
2365
        return Collections.unmodifiableList(this.featureTypes);
2366
    }
2367

    
2368
    @Override
2369
    public Feature createFeature(FeatureProvider data) throws DataException {
2370
        DefaultFeature feature = new DefaultFeature(this, data);
2371
        return feature;
2372
    }
2373

    
2374
    public Feature createFeature(FeatureProvider data, FeatureType type)
2375
        throws DataException {
2376
        // FIXME: falta por implementar
2377
        // Comprobar si es un subtipo del feature de data
2378
        // y construir un feature usando el subtipo.
2379
        // Probablemente requiera generar una copia del data.
2380
        throw new NotYetImplemented();
2381
    }
2382

    
2383
    @Override
2384
    public EditableFeature createNewFeature(FeatureType type,
2385
        Feature defaultValues) throws DataException {
2386
        try {
2387
            FeatureProvider data = createNewFeatureProvider(type);
2388
            DefaultEditableFeature feature =
2389
                new DefaultEditableFeature(this, data);
2390
            feature.initializeValues(defaultValues);
2391
            data.setNew(true);
2392

    
2393
            return feature;
2394
        } catch (Exception e) {
2395
            throw new CreateFeatureException(e, getName());
2396
        }
2397
    }
2398

    
2399
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2400
        throws DataException {
2401
        type = this.fixFeatureType((DefaultFeatureType) type);
2402
        FeatureProvider data = this.provider.createFeatureProvider(type);
2403
        data.setNew(true);
2404
        if (type.hasOID() && (data.getOID() == null)) {
2405
            data.setOID(this.provider.createNewOID());
2406
        } else {
2407
            data.setOID(this.getTemporalOID());
2408
        }
2409
        return data;
2410

    
2411
    }
2412

    
2413
    @Override
2414
    public EditableFeature createNewFeature(FeatureType type,
2415
        boolean defaultValues) throws DataException {
2416
        try {
2417
            FeatureProvider data = createNewFeatureProvider(type);
2418
            DefaultEditableFeature feature =
2419
                new DefaultEditableFeature(this, data);
2420
            if (defaultValues) {
2421
                feature.initializeValues();
2422
            }
2423
            return feature;
2424
        } catch (Exception e) {
2425
            throw new CreateFeatureException(e, getName());
2426
        }
2427
    }
2428

    
2429
    @Override
2430
    public EditableFeature createNewFeature(boolean defaultValues)
2431
        throws DataException {
2432
        return this.createNewFeature(this.getDefaultFeatureType(),
2433
            defaultValues);
2434
    }
2435

    
2436
    @Override
2437
    public EditableFeature createNewFeature() throws DataException {
2438
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2439
    }
2440

    
2441
    @Override
2442
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2443
        FeatureType ft = this.getDefaultFeatureType();
2444
        EditableFeature f = this.createNewFeature(ft, false);
2445
                for( FeatureAttributeDescriptor desc : ft ) {
2446
                        try {
2447
                                f.set(desc.getName(), defaultValues.get(desc.getName()));
2448
                        } catch(Throwable th) {
2449
                                // Ignore
2450
                        }
2451
                }
2452
        return f;
2453
    }
2454

    
2455
    @Override
2456
    public EditableFeatureType createFeatureType() {
2457
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2458
        return ftype;
2459
    }
2460

    
2461
    @Override
2462
    public EditableFeatureType createFeatureType(String id) {
2463
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2464
        return ftype;
2465
    }
2466

    
2467
    //
2468
    // ====================================================================
2469
    // Index related methods
2470
    //
2471

    
2472
    @Override
2473
    public FeatureIndexes getIndexes() {
2474
        return this.indexes;
2475
    }
2476

    
2477
    @Override
2478
    public FeatureIndex createIndex(FeatureType featureType,
2479
        String attributeName, String indexName) throws DataException {
2480
        return createIndex(null, featureType, attributeName, indexName);
2481
    }
2482

    
2483
    @Override
2484
    public FeatureIndex createIndex(String indexTypeName,
2485
        FeatureType featureType, String attributeName, String indexName)
2486
        throws DataException {
2487

    
2488
        return createIndex(indexTypeName, featureType, attributeName,
2489
            indexName, false, null);
2490
    }
2491

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

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

    
2505
        return createIndex(indexTypeName, featureType, attributeName,
2506
            indexName, true, observer);
2507
    }
2508

    
2509
    private FeatureIndex createIndex(String indexTypeName,
2510
        FeatureType featureType, String attributeName, String indexName,
2511
        boolean background, final Observer observer) throws DataException {
2512

    
2513
        checkNotInAppendMode();
2514
        FeatureIndexProviderServices index;
2515
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2516
                featureType, indexName,
2517
                featureType.getAttributeDescriptor(attributeName));
2518

    
2519
        try {
2520
            index.fill(background, observer);
2521
        } catch (FeatureIndexException e) {
2522
            throw new InitializeException(index.getName(), e);
2523
        }
2524

    
2525
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2526
        return index;
2527
    }
2528

    
2529
    //
2530
    // ====================================================================
2531
    // Transforms related methods
2532
    //
2533

    
2534
    @Override
2535
    public FeatureStoreTransforms getTransforms() {
2536
        return this.transforms;
2537
    }
2538

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

    
2602
    //
2603
    // ====================================================================
2604
    // UndoRedo related methods
2605
    //
2606

    
2607
    @Override
2608
    public boolean canRedo() {
2609
        return commands.canRedo();
2610
    }
2611

    
2612
    @Override
2613
    public boolean canUndo() {
2614
        return commands.canUndo();
2615
    }
2616

    
2617
    @Override
2618
    public void redo(int num) throws RedoException {
2619
        for (int i = 0; i < num; i++) {
2620
            redo();
2621
        }
2622
    }
2623

    
2624
    @Override
2625
    public void undo(int num) throws UndoException {
2626
        for (int i = 0; i < num; i++) {
2627
            undo();
2628
        }
2629
    }
2630

    
2631
    //
2632
    // ====================================================================
2633
    // Metadata related methods
2634
    //
2635

    
2636
    @Override
2637
    public Object getMetadataID() {
2638
        return this.provider.getSourceId();
2639
    }
2640

    
2641
    @Override
2642
    public void delegate(DynObject dynObject) {
2643
        this.metadata.delegate(dynObject);
2644
    }
2645

    
2646
    @Override
2647
    public DynClass getDynClass() {
2648
        return this.metadata.getDynClass();
2649
    }
2650

    
2651
    @Override
2652
    public Object getDynValue(String name) throws DynFieldNotFoundException {
2653
        try {
2654
            if (this.transforms.hasDynValue(name)) {
2655
                return this.transforms.getDynValue(name);
2656
            }
2657
            if (this.metadata.hasDynValue(name)) {
2658
                return this.metadata.getDynValue(name);
2659
            }
2660
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2661
                return this.provider.getProviderName();
2662
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2663
                return this.provider.getSourceId();
2664
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2665
                try {
2666
                    return this.getDefaultFeatureType();
2667
                } catch (DataException e) {
2668
                    return null;
2669
                }
2670
            }
2671
            return this.metadata.getDynValue(name);
2672
        } catch(Exception ex ) {
2673
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
2674
            return null;
2675
        }
2676
    }
2677

    
2678
    @Override
2679
    public boolean hasDynValue(String name) {
2680
        if (this.transforms.hasDynValue(name)) {
2681
            return true;
2682
        }
2683
        return this.metadata.hasDynValue(name);
2684
    }
2685

    
2686
    @Override
2687
    public boolean hasDynMethod(String name) {
2688
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2689
    }
2690

    
2691
    @Override
2692
    public void implement(DynClass dynClass) {
2693
        this.metadata.implement(dynClass);
2694
    }
2695

    
2696
    @Override
2697
    public Object invokeDynMethod(String name, Object[] args)
2698
        throws DynMethodException {
2699
        return this.metadata.invokeDynMethod(this, name, args);
2700
    }
2701

    
2702
    @Override
2703
    public Object invokeDynMethod(int code, Object[] args)
2704
        throws DynMethodException {
2705
        return this.metadata.invokeDynMethod(this, code, args);
2706
    }
2707

    
2708
    @Override
2709
    public void setDynValue(String name, Object value)
2710
        throws DynFieldNotFoundException {
2711
                if( this.transforms.hasDynValue(name) ) {
2712
                        this.transforms.setDynValue(name, value);
2713
                        return;
2714
                }
2715
        this.metadata.setDynValue(name, value);
2716

    
2717
    }
2718

    
2719
    /*
2720
     * (non-Javadoc)
2721
     *
2722
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2723
     */
2724
    @Override
2725
    public Set getMetadataChildren() {
2726
        return this.metadataChildren;
2727
    }
2728

    
2729
    /*
2730
     * (non-Javadoc)
2731
     *
2732
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2733
     */
2734
    @Override
2735
    public String getMetadataName() {
2736
        return this.provider.getProviderName();
2737
    }
2738

    
2739
    public FeatureTypeManager getFeatureTypeManager() {
2740
        return this.featureTypeManager;
2741
    }
2742

    
2743
    @Override
2744
    public long getFeatureCount() throws DataException {
2745
        if (featureCount == null) {
2746
            featureCount = this.provider.getFeatureCount();
2747
        }
2748
        if (this.isEditing()) {
2749
            if(this.isAppending()) {
2750
                try{
2751
                    throw new IllegalStateException();
2752
                } catch(IllegalStateException e) {
2753
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
2754
                }
2755
                return -1;
2756
            } else {
2757
                return featureCount
2758
                    + this.featureManager.getDeltaSize();
2759
            }
2760
        }
2761
        return featureCount;
2762
    }
2763

    
2764
    private Long getTemporalOID() {
2765
        return this.temporalOid++;
2766
    }
2767

    
2768
    @Override
2769
    public FeatureType getProviderFeatureType(String featureTypeId) {
2770
        if (featureTypeId == null) {
2771
            return this.defaultFeatureType;
2772
        }
2773
        FeatureType type;
2774
        Iterator iter = this.featureTypes.iterator();
2775
        while (iter.hasNext()) {
2776
            type = (FeatureType) iter.next();
2777
            if (type.getId().equals(featureTypeId)) {
2778
                return type;
2779
            }
2780
        }
2781
        return null;
2782
    }
2783

    
2784
    @Override
2785
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2786
        return ((DefaultFeature) feature).getData();
2787
    }
2788

    
2789
    @Override
2790
    public DataStore getStore() {
2791
        return this;
2792
    }
2793

    
2794
    @Override
2795
    public FeatureStore getFeatureStore() {
2796
        return this;
2797
    }
2798

    
2799
    @Override
2800
    public void createCache(String name, DynObject parameters)
2801
        throws DataException {
2802
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2803
        if (cache == null) {
2804
            throw new CreateException("FeaureCacheProvider", null);
2805
        }
2806
        cache.apply(this, provider);
2807
        provider = cache;
2808

    
2809
        featureCount = null;
2810
    }
2811

    
2812
    @Override
2813
    public FeatureCache getCache() {
2814
        return cache;
2815
    }
2816

    
2817
    @Override
2818
    public void clear() {
2819
        if (metadata != null) {
2820
            metadata.clear();
2821
        }
2822
    }
2823

    
2824
    @Override
2825
    public String getName() {
2826
        if( this.provider != null ) {
2827
            return this.provider.getName();
2828
        }
2829
        if( this.parameters instanceof HasAFile ) {
2830
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
2831
        }
2832
        return "unknow";
2833
    }
2834

    
2835
    @Override
2836
    public String getFullName() {
2837
        try {
2838
            if( this.provider!=null ) {
2839
                return this.provider.getFullName();
2840
            }
2841
            if( this.parameters instanceof HasAFile ) {
2842
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
2843
            }
2844
            return null;
2845
        } catch(Throwable th) {
2846
            return null;
2847
        }
2848
    }
2849

    
2850
    @Override
2851
    public String getProviderName() {
2852
        if( this.provider!=null ) {
2853
            return this.provider.getProviderName();
2854
        }
2855
        if( this.parameters != null ) {
2856
            return this.parameters.getDataStoreName();
2857
        }
2858
        return null;
2859

    
2860
    }
2861

    
2862
    @Override
2863
    public boolean isKnownEnvelope() {
2864
        return this.provider.isKnownEnvelope();
2865
    }
2866

    
2867
    @Override
2868
    public boolean hasRetrievedFeaturesLimit() {
2869
        return this.provider.hasRetrievedFeaturesLimit();
2870
    }
2871

    
2872
    @Override
2873
    public int getRetrievedFeaturesLimit() {
2874
        return this.provider.getRetrievedFeaturesLimit();
2875
    }
2876

    
2877
    @Override
2878
    public Interval getInterval() {
2879
        if( this.timeSupport!=null ) {
2880
            return this.timeSupport.getInterval();
2881
        }
2882
        try {
2883
            FeatureType type = this.getDefaultFeatureType();
2884
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
2885
            if( attr!=null ) {
2886
                Interval interval = attr.getInterval();
2887
                if( interval!=null ) {
2888
                    return interval;
2889
                }
2890
            }
2891
        } catch (DataException ex) {
2892
        }
2893
        return this.provider.getInterval();
2894
    }
2895

    
2896
    @Override
2897
    public Collection getTimes() {
2898
        if( this.timeSupport!=null ) {
2899
            return this.timeSupport.getTimes();
2900
        }
2901
        return this.provider.getTimes();
2902
    }
2903

    
2904
    @Override
2905
    public Collection getTimes(Interval interval) {
2906
        if( this.timeSupport!=null ) {
2907
            return this.timeSupport.getTimes(interval);
2908
        }
2909
        return this.provider.getTimes(interval);
2910
    }
2911

    
2912
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
2913
        if( this.isEditing() ) {
2914
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
2915
        }
2916
        if( !this.transforms.isEmpty() ) {
2917
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
2918
        }
2919
        FeatureType ft = this.defaultFeatureType;
2920
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
2921
        if( attr == null ) {
2922
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
2923
        }
2924
        EditableFeatureType eft = ft.getEditable();
2925
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
2926
        if( attr != null ) {
2927
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
2928
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
2929
            }
2930
            eft.remove(attr.getName());
2931
        }
2932
        EditableFeatureAttributeDescriptor attrTime = eft.add(
2933
            timeSupport.getAttributeName(), 
2934
            timeSupport.getDataType()
2935
        );
2936
        attrTime.setIsTime(true);
2937
        attrTime.setFeatureAttributeEmulator(timeSupport);
2938
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
2939
        this.defaultFeatureType = eft.getNotEditableCopy();
2940
        
2941
        this.timeSupport = timeSupport;
2942
    }
2943

    
2944
    @Override
2945
    @SuppressWarnings("CloneDoesntCallSuperClone")
2946
    public Object clone() throws CloneNotSupportedException {
2947

    
2948
        DataStoreParameters dsp = getParameters();
2949

    
2950
        DefaultFeatureStore cloned_store = null;
2951

    
2952
        try {
2953
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2954
                openStore(this.getProviderName(), dsp);
2955
            if (transforms != null) {
2956
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2957
                cloned_store.transforms.setStoreForClone(cloned_store);
2958
            }
2959
        } catch (Exception e) {
2960
            throw new CloneException(e);
2961
        }
2962
        return cloned_store;
2963

    
2964
    }
2965

    
2966
    @Override
2967
    public Feature getFeature(DynObject dynobject) {
2968
        if (dynobject instanceof DynObjectFeatureFacade){
2969
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2970
            return f;
2971
        }
2972
        return null;
2973
    }
2974

    
2975
    @Override
2976
    public Iterator iterator() {
2977
        try {
2978
            return this.getFeatureSet().fastIterator();
2979
        } catch (DataException ex) {
2980
            throw new RuntimeException(ex);
2981
        }
2982
    }
2983

    
2984
    @Override
2985
    public ExpressionBuilder createExpressionBuilder() {
2986
        ExpressionBuilder builder;
2987
        builder = ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2988
        return builder;
2989
    }
2990

    
2991
    @Override
2992
    public ExpressionBuilder createExpression() {
2993
        return createExpressionBuilder();
2994
    }
2995

    
2996
    public FeatureSet features() throws DataException {
2997
        // This is to avoid jython to create a property with this name
2998
        // to access method getFeatures.
2999
        return this.getFeatureSet();
3000
    }
3001

    
3002
    @Override
3003
    public DataStoreProviderFactory getProviderFactory() {
3004
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3005
        return factory;
3006
    }
3007

    
3008
    @Override
3009
    public void useCache(String providerName, DynObject parameters) throws DataException {
3010
        throw new UnsupportedOperationException();
3011
    }
3012

    
3013
    @Override
3014
    public boolean isBroken() {
3015
        return this.state.isBroken();
3016
    }
3017

    
3018
    @Override
3019
    public Throwable getBreakingsCause() {
3020
            return this.state.getBreakingsCause();
3021
    }
3022

    
3023
    @Override
3024
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3025
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3026
      if( !factory.supportNumericOID() ) {
3027
          return null;
3028
      }
3029
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3030
      return wrappedIndex;
3031
  }
3032

    
3033
    @Override
3034
    public FeatureReference getFeatureReference(String code) {
3035
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
3036
        return featureReference;
3037
    }
3038

    
3039
    @Override
3040
    public long getPendingChangesCount() {
3041
        if( this.featureManager==null ) {
3042
            return 0;
3043
        }
3044
        return this.featureManager.getPendingChangesCount();
3045
    }
3046

    
3047
    @Override
3048
    public ResourcesStorage getResourcesStorage() {
3049
        ResourcesStorage resourcesStorage;
3050
        try {
3051
            resourcesStorage = this.provider.getResourcesStorage();
3052
            if( resourcesStorage!=null ) {
3053
                return resourcesStorage;
3054
            }
3055
        } catch(Throwable th) {
3056
            
3057
        }
3058
        try {
3059
            DataServerExplorer explorer = this.getExplorer();
3060
            if( explorer==null ) {
3061
                return null;
3062
            }
3063
            return this.getExplorer().getResourcesStorage(this);
3064
        } catch (Exception ex) {
3065
            LOGGER.warn("Can't create resources storage",ex);
3066
            return null;
3067
        }
3068
    }
3069

    
3070
    @Override
3071
    public StoresRepository getStoresRepository() {
3072
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3073
        StoresRepository localRepository = this.provider.getStoresRepository();
3074
        if( localRepository==null ) {
3075
            return mainRepository;
3076
        }
3077
        StoresRepository repository = new BaseStoresRepository(this.getName());
3078
        repository.addRepository(localRepository);
3079
        repository.addRepository(mainRepository);
3080
        return repository;
3081
    }
3082

    
3083
    @Override
3084
    public Feature getSampleFeature() {
3085
            Feature sampleFeature;
3086
            try {
3087
                FeatureSelection theSelection = this.getFeatureSelection();
3088
                if( theSelection!=null && !theSelection.isEmpty() ) {
3089
                    sampleFeature = theSelection.first();
3090
                } else {
3091
                    sampleFeature = this.first();
3092
                }
3093
                if( sampleFeature==null ) {
3094
                    sampleFeature = this.createNewFeature();
3095
                }
3096
            } catch (DataException ex) {
3097
                return null;
3098
            }
3099
            return sampleFeature;
3100
    }
3101

    
3102
    @Override
3103
    public boolean supportReferences() {
3104
        try {
3105
            return this.getDefaultFeatureType().supportReferences();
3106
        } catch (Exception ex) {
3107
            return false;
3108
        }
3109
    }
3110

    
3111
    @Override
3112
    public boolean isTemporary() {
3113
        if( this.provider==null ) {
3114
            return true;
3115
        }
3116
        return this.provider.isTemporary();
3117
    }
3118
    
3119
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3120
        // FIXME this don't work for Store.fType.size() > 1
3121
        FeatureTypeManager manager = this.featureTypeManager;
3122
         if (manager==null) {
3123
             return null;
3124
         }
3125
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3126
         if (originalFeatureType==null) {
3127
             return null;
3128
         }
3129
         return originalFeatureType.getCopy();
3130
    }
3131
}