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

History | View | Annotate | Download (104 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

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

    
176
import org.slf4j.Logger;
177
import org.slf4j.LoggerFactory;
178

    
179
@SuppressWarnings("UseSpecificCatch")
180
public class DefaultFeatureStore extends AbstractDisposable implements
181
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
182

    
183
    private static final Logger LOG = LoggerFactory
184
        .getLogger(DefaultFeatureStore.class);
185

    
186
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
187

    
188
    private DataStoreParameters parameters = null;
189
    private FeatureSelection selection;
190
    private FeatureLocks locks;
191

    
192
    private DelegateWeakReferencingObservable delegateObservable =
193
        new DelegateWeakReferencingObservable(this);
194

    
195
    private FeatureCommandsStack commands;
196
    
197
    /*
198
    TODO: Sustituir estos tres manager por un EditingManager
199
    */
200
    private FeatureTypeManager featureTypeManager;
201
    private FeatureManager featureManager;
202
    private SpatialManager spatialManager;
203

    
204
    private FeatureType defaultFeatureType = null;
205
    private List featureTypes = new ArrayList();
206

    
207
    private int mode = MODE_QUERY;
208
    private long versionOfUpdate = 0;
209
    private boolean hasStrongChanges = true;
210
    private boolean hasInserts = true;
211

    
212
    private DefaultDataManager dataManager = null;
213

    
214
    private FeatureStoreProvider provider = null;
215

    
216
    private DefaultFeatureIndexes indexes;
217

    
218
    private DefaultFeatureStoreTransforms transforms;
219

    
220
    DelegatedDynObject metadata;
221

    
222
    private Set metadataChildren;
223

    
224
    private Long featureCount = null;
225

    
226
    private long temporalOid = 0;
227

    
228
    private FeatureCacheProvider cache;
229

    
230
    StateInformation state;
231

    
232
    FeatureStoreTimeSupport timeSupport;
233

    
234

    
235
    private class StateInformation extends HashMap<Object, Object> {
236

    
237
        private static final long serialVersionUID = 4109026189635185666L;
238

    
239
        private boolean broken;
240
        private Throwable breakingsCause;
241

    
242
        @SuppressWarnings("OverridableMethodCallInConstructor")
243
        public StateInformation() {
244
            this.clear();
245
        }
246

    
247
        @Override
248
        public void clear() {
249
            this.broken = false;
250
            this.breakingsCause = null;
251
            super.clear();
252
        }
253

    
254
        public boolean isBroken() {
255
            return this.broken;
256
        }
257

    
258
        public void broken() {
259
            this.broken = true;
260
        }
261

    
262
        public Throwable getBreakingsCause() {
263
            return this.breakingsCause;
264
        }
265

    
266
        public void setBreakingsCause(Throwable cause) {
267
            if( this.breakingsCause==null ) {
268
                this.breakingsCause = cause;
269
            }
270
            this.broken = true;
271
        }
272
    }
273

    
274

    
275

    
276
    /*
277
     * TODO:
278
     *
279
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
280
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
281
     * featureType al que se le han cambiado las reglas de validacion cuando
282
     * hasStrongChanges=false.
283
     */
284

    
285
    public DefaultFeatureStore() {
286
        this.state = new StateInformation();
287
    }
288

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

    
293
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
294

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

    
300
        this.dataManager = (DefaultDataManager) dataManager;
301

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

    
310
    }
311

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

    
321
    @Override
322
    public DataStoreParameters getParameters() {
323
        return parameters;
324
    }
325

    
326
    public int getMode() {
327
        return this.mode;
328
    }
329

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

    
335
    @Override
336
    public UnmodifiableBasicMap<String,DataStore> getChildren() {
337
        return this.provider.getChildren();
338
    }
339

    
340
    @Override
341
    public FeatureStoreProvider getProvider() {
342
        return this.provider;
343
    }
344

    
345
    public FeatureManager getFeatureManager() {
346
        return this.featureManager;
347
    }
348

    
349
    @Override
350
    public void setFeatureTypes(List types, FeatureType defaultType) {
351
        this.featureTypes = types;
352
        this.defaultFeatureType = defaultType;
353
    }
354

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

    
369
    @Override
370
    public void refresh() throws OpenException, InitializeException {
371
        if (this.mode != MODE_QUERY) {
372
            throw new IllegalStateException();
373
        }
374
        this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH);
375
        if( state.isBroken() ) {
376
            this.load(state);
377
        } else {
378
            this.featureCount = null;
379
            this.provider.refresh();
380
        }
381
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
382
    }
383

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

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

    
425
        if (this.featureTypeManager != null) {
426
            this.featureTypeManager.dispose();
427
            this.featureTypeManager = null;
428
        }
429

    
430
        this.featureManager = null;
431
        this.spatialManager = null;
432

    
433
        this.parameters = null;
434
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
435
        if (delegateObservable != null) {
436
            this.delegateObservable.deleteObservers();
437
            this.delegateObservable = null;
438
        }
439
    }
440

    
441
    @Override
442
    public boolean allowWrite() {
443
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
444
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
445
            return false;
446
        }
447
        return this.provider.allowWrite();
448
    }
449

    
450
    @Override
451
    public boolean canWriteGeometry(int geometryType) throws DataException {
452
        return this.provider.canWriteGeometry(geometryType, 0);
453
    }
454

    
455
    @Override
456
    public DataServerExplorer getExplorer() throws ReadException,
457
        ValidateDataParametersException {
458
        if( this.state.isBroken() ) {
459
            try {
460
                return this.provider.getExplorer();
461
            } catch(Throwable th) {
462
                return null;
463
            }
464
        } else {
465
            return this.provider.getExplorer();
466
        }
467
    }
468

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

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

    
525
    /**
526
     * @throws org.gvsig.fmap.dal.exception.DataException
527
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
528
     */
529
    @Override
530
    public IProjection getSRSDefaultGeometry() throws DataException {
531
        return this.getDefaultFeatureType().getDefaultSRS();
532
    }
533

    
534
    @Override
535
    public FeatureSelection createDefaultFeatureSelection()
536
        throws DataException {
537
        return new DefaultFeatureSelection(this);
538
    }
539

    
540
    @Override
541
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
542
        throws DataException {
543
        if (type.hasOID()) {
544
            return new DefaultFeatureProvider(type,
545
                this.provider.createNewOID());
546
        }
547
        return new DefaultFeatureProvider(type);
548
    }
549

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

    
585
        }
586

    
587
        if (evaluatedAttr.isEmpty()) {
588
            evaluatedAttr = null;
589
        }
590

    
591
        state.set("evaluatedAttributes", evaluatedAttr);
592
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
593

    
594
    }
595

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

    
634
    private void load(StateInformation state) {
635
        this.featureTypes = new ArrayList();
636
        this.defaultFeatureType = null;
637
        this.featureCount = null;
638

    
639
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
640
        try {
641
            intialize(dataManager, params);
642
        } catch(Throwable th) {
643
            state.setBreakingsCause(th);
644
        }
645

    
646
        try {
647
            DataStoreProvider prov = dataManager.createProvider(
648
                getStoreProviderServices(),
649
                params
650
            );
651
            setProvider(prov);
652
        } catch(Throwable th) {
653
            LOG.warn("Can't load store from state.", th);
654
            state.setBreakingsCause(th);
655
        }
656
        try {
657
            selection = (FeatureSelection) state.get("selection");
658
        } catch(Throwable th) {
659
            state.setBreakingsCause(th);
660
        }
661

    
662
        try {
663
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
664
            this.transforms.setFeatureStore(this);
665
            for( FeatureStoreTransform transform : this.transforms ) {
666
                try {
667
                    transform.setUp();
668
                } catch(Throwable th) {
669
                    state.setBreakingsCause(th);
670
                }
671
            }
672
        } catch(Throwable th) {
673
            state.setBreakingsCause(th);
674
        }
675

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

    
707
                    }
708

    
709
            }
710
        } catch(Throwable th) {
711
            state.setBreakingsCause(th);
712
        }
713

    
714

    
715
        try {
716
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
717
            FeatureType ftype;
718

    
719
            if (defaultFeatureType == null ||
720
                    defaultFeatureType.getId() == null ||
721
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
722

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

    
742
        LOG.info("load() broken:{}, {}, {}.",
743
                new Object[] { state.isBroken(), this.getProviderName(), params }
744
        );
745
    }
746

    
747
        public DataStoreProviderServices getStoreProviderServices() {
748
                return this;
749
        }
750

    
751
    public static void registerPersistenceDefinition() {
752
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
753
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
754
            DynStruct definition =
755
                manager.addDefinition(DefaultFeatureStore.class,
756
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
757
                        + " Persistent definition", null, null);
758
            definition.addDynFieldString("dataStoreName").setMandatory(true)
759
                .setPersistent(true);
760

    
761
            definition.addDynFieldObject("parameters")
762
                .setClassOfValue(DynObject.class).setMandatory(true)
763
                .setPersistent(true);
764

    
765
            definition.addDynFieldObject("selection")
766
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
767
                .setPersistent(true);
768

    
769
            definition.addDynFieldObject("transforms")
770
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
771
                .setMandatory(true).setPersistent(true);
772

    
773
            definition.addDynFieldMap("evaluatedAttributes")
774
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
775
                .setMandatory(false).setPersistent(true);
776

    
777
            definition.addDynFieldString("defaultFeatureTypeId")
778
                .setMandatory(true).setPersistent(true);
779
        }
780
    }
781

    
782
    public static void registerMetadataDefinition() throws MetadataException {
783
        MetadataManager manager = MetadataLocator.getMetadataManager();
784
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
785
            DynStruct metadataDefinition =
786
                manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
787
            metadataDefinition.extend(manager
788
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
789
        }
790
    }
791

    
792
    //
793
    // ====================================================================
794
    // Gestion de la seleccion
795
    //
796

    
797
    @Override
798
    public void setSelection(DataSet selection) throws DataException {
799
        this.setSelection((FeatureSet) selection);
800
    }
801

    
802
    @Override
803
    public DataSet createSelection() throws DataException {
804
        return createFeatureSelection();
805
    }
806

    
807
    @Override
808
    public DataSet getSelection() throws DataException {
809
        return this.getFeatureSelection();
810
    }
811

    
812
    @Override
813
    public void setSelection(FeatureSet selection) throws DataException {
814
        setSelection(selection, true);
815
    }
816

    
817
    public void setSelection(FeatureSet selection, boolean undoable)
818
        throws DataException {
819
        if (selection == null) {
820
            if (undoable) {
821
                throw new SelectionNotAllowedException(getName());
822
            }
823

    
824
        } else {
825
            if (selection.equals(this.selection)) {
826
                return;
827
            }
828
            if (!selection.isFromStore(this)) {
829
                throw new SelectionNotAllowedException(getName());
830
            }
831
        }
832

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

    
871
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
872
    }
873

    
874
    @Override
875
    public FeatureSelection createFeatureSelection() throws DataException {
876
        return this.provider.createFeatureSelection();
877
    }
878

    
879
    @Override
880
    public FeatureSelection getFeatureSelection() throws DataException {
881
        if (selection == null) {
882
            this.selection = createFeatureSelection();
883
            this.selection.addObserver(this);
884
        }
885
        return selection;
886
    }
887

    
888
    //
889
    // ====================================================================
890
    // Gestion de notificaciones
891
    //
892

    
893
    @Override
894
    public void notifyChange(FeatureStoreNotification storeNotification) {
895
        try {
896
            delegateObservable.notifyObservers(storeNotification);
897
        } catch (Throwable ex) {
898
            LOG.warn("Problems notifying changes in the store '"+this.getName()+" ("+storeNotification.getType()+").",ex);
899
        }
900
    }
901

    
902
    @Override
903
    public void notifyChange(String notification) {
904
        if (delegateObservable != null) {
905
            notifyChange(new DefaultFeatureStoreNotification(this, notification));
906
        }
907

    
908
    }
909

    
910
    @Override
911
    public void notifyChange(String notification, FeatureProvider data) {
912
        Feature f = null;
913
        try {
914
            f = createFeature(data);
915
        } catch (Throwable ex) {
916
            LOG.warn("Problems creating a feature to notifying changes in the store '"+this.getName()+" ("+notification+").",ex);
917
        }
918
        notifyChange(notification, f);
919
    }
920

    
921
    public void notifyChange(String notification, Feature feature) {
922
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
923
            feature));
924
    }
925

    
926
    public void notifyChange(String notification, Command command) {
927
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
928
            command));
929
    }
930

    
931
    public void notifyChange(String notification, EditableFeatureType type) {
932
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
933
            type));
934
    }
935

    
936
    @Override
937
    public void notifyChange(String notification, Resource resource) {
938
        notifyChange(new DefaultFeatureStoreNotification(this,
939
            DataStoreNotification.RESOURCE_CHANGED));
940
    }
941

    
942
    //
943
    // ====================================================================
944
    // Gestion de bloqueos
945
    //
946

    
947
    @Override
948
    public boolean isLocksSupported() {
949
        return this.provider.isLocksSupported();
950
    }
951

    
952
    @Override
953
    public FeatureLocks getLocks() throws DataException {
954
        if (!this.provider.isLocksSupported()) {
955
            LOG.warn("Locks not supported");
956
            return null;
957
        }
958
        if (locks == null) {
959
            this.locks = this.provider.createFeatureLocks();
960
        }
961
        return locks;
962
    }
963

    
964
    //
965
    // ====================================================================
966
    // Interface Observable
967
    //
968

    
969
    @Override
970
    public void disableNotifications() {
971
        this.delegateObservable.disableNotifications();
972

    
973
    }
974

    
975
    @Override
976
    public void enableNotifications() {
977
        this.delegateObservable.enableNotifications();
978
    }
979

    
980
    @Override
981
    public void beginComplexNotification() {
982
        this.delegateObservable.beginComplexNotification();
983

    
984
    }
985

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

    
990
    }
991

    
992
    @Override
993
    public void addObserver(Observer observer) {
994
        if (delegateObservable != null) {
995
            this.delegateObservable.addObserver(observer);
996
        }
997
    }
998

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

    
1006
    @Override
1007
    public void deleteObservers() {
1008
        this.delegateObservable.deleteObservers();
1009

    
1010
    }
1011

    
1012
    //
1013
    // ====================================================================
1014
    // Interface Observer
1015
    //
1016
    // Usado para observar:
1017
    // - su seleccion
1018
    // - sus bloqueos
1019
    // - sus recursos
1020
    //
1021

    
1022
    @Override
1023
    public void update(Observable observable, Object notification) {
1024
        if (observable instanceof FeatureSet) {
1025
            if (observable == this.selection) {
1026
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1027
            } else if (observable == this.locks) {
1028
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1029
            }
1030

    
1031
        } else if (observable instanceof FeatureStoreProvider) {
1032
            if (observable == this.provider) {
1033

    
1034
            }
1035
        } else if (observable instanceof FeatureReferenceSelection) {
1036
            if(notification instanceof String){
1037
                    this.notifyChange((String)notification);
1038
            }
1039
        }
1040
    }
1041

    
1042
    //
1043
    // ====================================================================
1044
    // Edicion
1045
    //
1046

    
1047
    private void newVersionOfUpdate() {
1048
        this.versionOfUpdate++;
1049
    }
1050

    
1051
    private long currentVersionOfUpdate() {
1052
        return this.versionOfUpdate;
1053
    }
1054

    
1055
    private void checkInEditingMode() throws NeedEditingModeException {
1056
        if (mode != MODE_FULLEDIT) {
1057
            throw new NeedEditingModeException(this.getName());
1058
        }
1059
    }
1060

    
1061
    private void checkNotInAppendMode() throws IllegalStateException {
1062
        if (mode == MODE_APPEND) {
1063
                        throw new IllegalStateException("Error: store "
1064
                                        + this.getFullName() + " is in append mode");
1065
        }
1066
    }
1067

    
1068
    private void checkIsOwnFeature(Feature feature)
1069
        throws IllegalFeatureException {
1070
        if (((DefaultFeature) feature).getStore() != this) {
1071
            throw new IllegalFeatureException(this.getName());
1072
        }
1073
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1074
        // fixFeatureType((DefaultFeatureType) feature.getType());
1075
    }
1076

    
1077
    private void exitEditingMode() {
1078
        if (commands != null) {
1079
            commands.clear();
1080
            commands = null;
1081
        }
1082

    
1083
        if (featureTypeManager != null) {
1084
            featureTypeManager.dispose();
1085
            featureTypeManager = null;
1086

    
1087
        }
1088

    
1089
        // TODO implementar un dispose para estos dos
1090
        featureManager = null;
1091
        spatialManager = null;
1092

    
1093
        featureCount = null;
1094

    
1095
        mode = MODE_QUERY;
1096
        hasStrongChanges = true; // Lo deja a true por si las moscas
1097
        hasInserts = true;
1098
    }
1099

    
1100
    @Override
1101
    synchronized public void edit() throws DataException {
1102
        edit(MODE_FULLEDIT);
1103
    }
1104

    
1105
    @Override
1106
    synchronized public void edit(int mode) throws DataException {
1107
        LOG.debug("Starting editing in mode: {}", mode);
1108
        try {
1109
            if (this.mode != MODE_QUERY) {
1110
                throw new AlreadyEditingException(this.getName());
1111
            }
1112
            if (!this.provider.supportsAppendMode()) {
1113
                mode = MODE_FULLEDIT;
1114
            }
1115
            switch (mode) {
1116
            case MODE_QUERY:
1117
                throw new IllegalStateException(this.getName());
1118

    
1119
            case MODE_FULLEDIT:
1120
                if (!this.transforms.isEmpty()) {
1121
                    throw new IllegalStateException(this.getName());
1122
                }
1123
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
1124
                invalidateIndexes();
1125
                featureManager = new FeatureManager();
1126
                featureTypeManager = new FeatureTypeManager(this);
1127
                spatialManager = new SpatialManager(this, provider.getEnvelope());
1128

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

    
1154
    private void invalidateIndexes() {
1155
        setIndexesValidStatus(false);
1156
    }
1157

    
1158
    private void setIndexesValidStatus(boolean valid) {
1159
        FeatureIndexes theIndexes = getIndexes();
1160
        LOG.debug("Setting the store indexes to valid status {}: {}", (valid
1161
            ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1162
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1163
            FeatureIndex index = (FeatureIndex) iterator.next();
1164
            if (index instanceof FeatureIndexProviderServices) {
1165
                FeatureIndexProviderServices indexServices =
1166
                    (FeatureIndexProviderServices) index;
1167
                indexServices.setValid(valid);
1168
            }
1169
        }
1170
    }
1171

    
1172
    private void updateIndexes() throws FeatureIndexException {
1173
        FeatureIndexes theIndexes = getIndexes();
1174
        LOG.debug("Refilling indexes: {}", theIndexes);
1175
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1176
            FeatureIndex index = (FeatureIndex) iterator.next();
1177
            if (index instanceof FeatureIndexProviderServices) {
1178
                FeatureIndexProviderServices indexServices =
1179
                    (FeatureIndexProviderServices) index;
1180
                indexServices.fill(true, null);
1181
            }
1182
        }
1183
    }
1184

    
1185
    private void waitForIndexes() {
1186
        FeatureIndexes theIndexes = getIndexes();
1187
        LOG.debug("Waiting for indexes to finish filling: {}", theIndexes);
1188
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1189
            FeatureIndex index = (FeatureIndex) iterator.next();
1190
            if (index instanceof FeatureIndexProviderServices) {
1191
                FeatureIndexProviderServices indexServices =
1192
                    (FeatureIndexProviderServices) index;
1193
                indexServices.waitForIndex();
1194
            }
1195
        }
1196
    }
1197

    
1198
    private void disposeIndexes() {
1199
        FeatureIndexes theIndexes = getIndexes();
1200
        LOG.debug("Disposing indexes: {}", theIndexes);
1201
        if( theIndexes==null ) {
1202
            return;
1203
        }
1204
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1205
            FeatureIndex index = (FeatureIndex) iterator.next();
1206
            if (index instanceof FeatureIndexProviderServices) {
1207
                FeatureIndexProviderServices indexServices =
1208
                    (FeatureIndexProviderServices) index;
1209
                indexServices.dispose();
1210
            }
1211
        }
1212
    }
1213

    
1214
    @Override
1215
    public boolean isEditing() {
1216
        return mode == MODE_FULLEDIT;
1217
    }
1218

    
1219
    @Override
1220
    public boolean isAppending() {
1221
        return mode == MODE_APPEND;
1222
    }
1223

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

    
1253
    @Override
1254
    public void delete(Feature feature) throws DataException {
1255
        this.commands.delete(feature);
1256
    }
1257

    
1258
    synchronized public void doDelete(Feature feature) throws DataException {
1259
        try {
1260
            checkInEditingMode();
1261
            checkIsOwnFeature(feature);
1262
            if (feature instanceof EditableFeature) {
1263
                throw new StoreDeleteEditableFeatureException(getName());
1264
            }
1265
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1266

    
1267
            //Update the featureManager and the spatialManager
1268
            featureManager.delete(feature.getReference());
1269
            spatialManager.deleteFeature(feature);
1270

    
1271
            newVersionOfUpdate();
1272
            hasStrongChanges = true;
1273
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1274
        } catch (Exception e) {
1275
            throw new StoreDeleteFeatureException(e, this.getName());
1276
        }
1277
    }
1278

    
1279
    private static EditableFeature lastChangedFeature = null;
1280

    
1281
    @Override
1282
    public synchronized void insert(EditableFeature feature)
1283
        throws DataException {
1284
        LOG.debug("In editing mode {}, insert feature: {}", mode, feature);
1285
        try {
1286
            switch (mode) {
1287
            case MODE_QUERY:
1288
                throw new NeedEditingModeException(this.getName());
1289

    
1290
            case MODE_APPEND:
1291
                checkIsOwnFeature(feature);
1292
                if (feature.getSource() != null) {
1293
                    throw new NoNewFeatureInsertException(this.getName());
1294
                }
1295
                this.featureCount = null;
1296
                notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1297
                feature.validate(Feature.UPDATE);
1298
                provider.append(((DefaultEditableFeature) feature).getData());
1299
                hasStrongChanges = true;
1300
                hasInserts = true;
1301
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1302
                break;
1303

    
1304
            case MODE_FULLEDIT:
1305
                if (feature.getSource() != null) {
1306
                    throw new NoNewFeatureInsertException(this.getName());
1307
                }
1308
                commands.insert(feature);
1309
            }
1310
        } catch (Exception e) {
1311
            throw new StoreInsertFeatureException(e, this.getName());
1312
        }
1313
    }
1314

    
1315
    synchronized public void doInsert(EditableFeature feature)
1316
        throws DataException {
1317
        checkIsOwnFeature(feature);
1318

    
1319
        waitForIndexes();
1320

    
1321
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1322
        newVersionOfUpdate();
1323
        if ((lastChangedFeature == null)
1324
            || (lastChangedFeature.getSource() != feature.getSource())) {
1325
            lastChangedFeature = feature;
1326
            feature.validate(Feature.UPDATE);
1327
            lastChangedFeature = null;
1328
        }
1329
        //Update the featureManager and the spatialManager
1330
        ((DefaultEditableFeature) feature).setInserted(true);
1331
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1332

    
1333

    
1334
        featureManager.add(newFeature);
1335
        spatialManager.insertFeature(newFeature);
1336

    
1337
        hasStrongChanges = true;
1338
        hasInserts = true;
1339
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1340
    }
1341

    
1342
    @Override
1343
    public void update(EditableFeature feature)
1344
    throws DataException {
1345
        if ((feature).getSource() == null) {
1346
            insert(feature);
1347
            return;
1348
        }
1349
        commands.update(feature, feature.getSource());
1350
    }
1351

    
1352
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1353
        throws DataException {
1354
        try {
1355
            checkInEditingMode();
1356
            checkIsOwnFeature(feature);
1357
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature);
1358
            newVersionOfUpdate();
1359
            if ((lastChangedFeature == null)
1360
                || (lastChangedFeature.getSource() != feature.getSource())) {
1361
                lastChangedFeature = feature;
1362
                feature.validate(Feature.UPDATE);
1363
                lastChangedFeature = null;
1364
            }
1365

    
1366
            //Update the featureManager and the spatialManager
1367
            Feature newf = feature.getNotEditableCopy();
1368
            featureManager.update(newf, oldFeature);
1369
            spatialManager.updateFeature(newf, oldFeature);
1370

    
1371
            hasStrongChanges = true;
1372
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1373
        } catch (Exception e) {
1374
            throw new StoreUpdateFeatureException(e, this.getName());
1375
        }
1376
    }
1377

    
1378
    @Override
1379
    synchronized public void redo() throws RedoException {
1380
        Command redo = commands.getNextRedoCommand();
1381
        try {
1382
            checkInEditingMode();
1383
        } catch (NeedEditingModeException ex) {
1384
            throw new RedoException(redo, ex);
1385
        }
1386
        notifyChange(FeatureStoreNotification.BEFORE_REDO, redo);
1387
        newVersionOfUpdate();
1388
        commands.redo();
1389
        hasStrongChanges = true;
1390
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1391
    }
1392

    
1393
    @Override
1394
    synchronized public void undo() throws UndoException {
1395
        Command undo = commands.getNextUndoCommand();
1396
        try {
1397
            checkInEditingMode();
1398
        } catch (NeedEditingModeException ex) {
1399
            throw new UndoException(undo, ex);
1400
        }
1401
        notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo);
1402
        newVersionOfUpdate();
1403
        commands.undo();
1404
        hasStrongChanges = true;
1405
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1406
    }
1407

    
1408
    @Override
1409
    public List getRedoInfos() {
1410
        if (isEditing() && (commands != null)) {
1411
            return commands.getRedoInfos();
1412
        } else {
1413
            return null;
1414
        }
1415
    }
1416

    
1417
    @Override
1418
    public List getUndoInfos() {
1419
        if (isEditing() && (commands != null)) {
1420
            return commands.getUndoInfos();
1421
        } else {
1422
            return null;
1423
        }
1424
    }
1425

    
1426
    public synchronized FeatureCommandsStack getCommandsStack()
1427
        throws DataException {
1428
        checkInEditingMode();
1429
        return commands;
1430
    }
1431

    
1432
    @Override
1433
    synchronized public void cancelEditing() throws DataException {
1434
        if( spatialManager!=null ) {
1435
            spatialManager.cancelModifies();
1436
        }
1437
        try {
1438
            switch (mode) {
1439
            case MODE_QUERY:
1440
                throw new NeedEditingModeException(this.getName());
1441

    
1442
            case MODE_APPEND:
1443
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1444
                provider.abortAppend();
1445
                exitEditingMode();
1446
                ((FeatureSelection) this.getSelection()).deselectAll();
1447
                updateIndexes();
1448
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1449

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

    
1468
    @Override
1469
    synchronized public void finishEditing() throws DataException {
1470
        LOG.debug("finish editing of mode: {}", mode);
1471
        try {
1472

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

    
1484
            case MODE_APPEND:
1485
                if( selection!=null ) {
1486
                    selection = null;
1487
                }
1488
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1489
                saveDALFile();
1490
                provider.endAppend();
1491
                exitEditingMode();
1492
                this.updateComputedFields(computedFields);
1493
                loadDALFile();
1494
                updateIndexes();
1495
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1496
                break;
1497

    
1498
            case MODE_FULLEDIT:
1499
                if (hasStrongChanges && !this.allowWrite()) {
1500
                    throw new WriteNotAllowedException(getName());
1501
                }
1502
                saveDALFile();
1503
                if(featureManager.isSelectionCompromised() && selection!=null ) {
1504
                    selection = null;
1505
                }
1506
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1507
                if (hasStrongChanges) {
1508
                    validateFeatures(Feature.FINISH_EDITING);
1509

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

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

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

    
1651
        case MODE_APPEND:
1652
          this.provider.endAppend();
1653
          exitEditingMode();
1654
          invalidateIndexes();
1655
          this.provider.beginAppend();
1656
          hasInserts = false;
1657
          break;
1658

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

    
1675
          commands =
1676
            new DefaultFeatureCommandsStack(this, featureManager,
1677
              spatialManager, featureTypeManager);
1678
          featureCount = null;
1679
          hasStrongChanges = false;
1680
          hasInserts = false;
1681
          break;
1682
        }
1683
      } catch (Exception e) {
1684
        throw new FinishEditingException(e);
1685
      }
1686
    }
1687

    
1688
    @Override
1689
    synchronized public boolean canCommitChanges() throws DataException {
1690
        if ( !this.allowWrite()) {
1691
                return false;
1692
        }
1693
            switch (mode) {
1694
            default:
1695
        case MODE_QUERY:
1696
                return false;
1697

    
1698
        case MODE_APPEND:
1699
                return true;
1700

    
1701
        case MODE_FULLEDIT:
1702
            List types = this.getFeatureTypes();
1703
            for( int i=0; i<types.size(); i++ ) {
1704
                    Object type = types.get(i);
1705
                    if( type instanceof DefaultEditableFeatureType ) {
1706
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1707
                                    return false;
1708
                            }
1709
                    }
1710
            }
1711
            return true;
1712
            }
1713
    }
1714

    
1715
    @Override
1716
    public void beginEditingGroup(String description)
1717
        throws NeedEditingModeException {
1718
        checkInEditingMode();
1719
        commands.startComplex(description);
1720
    }
1721

    
1722
    @Override
1723
    public void endEditingGroup() throws NeedEditingModeException {
1724
        checkInEditingMode();
1725
        commands.endComplex();
1726
    }
1727

    
1728
    @Override
1729
    public boolean isAppendModeSupported() {
1730
        return this.provider.supportsAppendMode();
1731
    }
1732

    
1733
    @Override
1734
    public void export(DataServerExplorer explorer, String provider,
1735
        NewFeatureStoreParameters params) throws DataException {
1736

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

    
1751
            }
1752
            explorer.add(provider, params, true);
1753

    
1754
            DataManager manager = DALLocator.getDataManager();
1755
            target = (FeatureStore) manager.openStore(provider, params);
1756
            FeatureType targetType = target.getDefaultFeatureType();
1757

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

    
1789
    //
1790
    // ====================================================================
1791
    // Obtencion de datos
1792
    // getDataCollection, getFeatureCollection
1793
    //
1794

    
1795
    @Override
1796
    public DataSet getDataSet() throws DataException {
1797
        checkNotInAppendMode();
1798
        FeatureQuery query =
1799
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1800
        return new DefaultFeatureSet(this, query);
1801
    }
1802

    
1803
    @Override
1804
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1805
        checkNotInAppendMode();
1806
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1807
    }
1808

    
1809
    @Override
1810
    public void getDataSet(Observer observer) throws DataException {
1811
        checkNotInAppendMode();
1812
        this.getFeatureSet(null, observer);
1813
    }
1814

    
1815
    @Override
1816
    public void getDataSet(DataQuery dataQuery, Observer observer)
1817
        throws DataException {
1818
        checkNotInAppendMode();
1819
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1820
    }
1821

    
1822
    @Override
1823
    public FeatureSet getFeatureSet() throws DataException {
1824
        return this.getFeatureSet((FeatureQuery)null);
1825
    }
1826

    
1827
    @Override
1828
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1829
        throws DataException {
1830
        checkNotInAppendMode();
1831
        if( featureQuery==null ) {
1832
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1833
        }
1834
        return new DefaultFeatureSet(this, featureQuery);
1835
    }
1836

    
1837
    @Override
1838
    public FeatureSet getFeatureSet(String filter) throws DataException {
1839
        return this.getFeatureSet(filter, null, true);
1840
    }
1841

    
1842
    @Override
1843
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
1844
        return this.getFeatureSet(filter, sortBy, true);
1845
    }
1846

    
1847
    @Override
1848
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
1849
        return this.getFeatureSet(filter, null, true);
1850
    }
1851
    
1852
    @Override
1853
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
1854
        return this.getFeatureSet(filter, sortBy, true);
1855
    }
1856

    
1857
    @Override
1858
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
1859
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1860
        return this.getFeatureSet(query);
1861
    }
1862
    
1863
    @Override
1864
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
1865
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1866
        return this.getFeatureSet(query);
1867
    }
1868
    
1869
    @Override
1870
    public List<Feature> getFeatures(String filter)  {
1871
        return this.getFeatures(filter, null, true);
1872
    }
1873

    
1874
    @Override
1875
    public List<Feature> getFeatures(String filter, String sortBy)  {
1876
        return this.getFeatures(filter, sortBy, true);
1877
    }
1878

    
1879
    @Override
1880
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
1881
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1882
        return this.getFeatures(query, 100);
1883
    }
1884
    
1885
    @Override
1886
    public List<Feature> getFeatures(Expression filter)  {
1887
        return this.getFeatures(filter, null, true);
1888
    }
1889

    
1890
    @Override
1891
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
1892
        return this.getFeatures(filter, sortBy, true);
1893
    }
1894

    
1895
    @Override
1896
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
1897
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1898
        return this.getFeatures(query, 100);
1899
    }
1900
    
1901
    @Override
1902
    public List<Feature> getFeatures(FeatureQuery query)  {
1903
        return this.getFeatures(query, 100);
1904
    }
1905
    
1906
    @Override
1907
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
1908
        try {
1909
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
1910
            return pager.asList();
1911
        } catch (BaseException ex) {
1912
            throw new RuntimeException("Can't create the list of features.", ex);
1913
        }
1914
    }
1915

    
1916
    @Override
1917
    public List<Feature> getFeatures() {
1918
        return this.getFeatures(null, 500);
1919
    }
1920

    
1921
    @Override
1922
    public Feature first() throws DataException {
1923
        return this.findFirst((FeatureQuery)null);
1924
    }
1925
    
1926
    @Override
1927
    public Feature findFirst(String filter) throws DataException {
1928
        return this.findFirst(filter, null, true);
1929
    }
1930

    
1931
    @Override
1932
    public Feature findFirst(String filter, String sortBy) throws DataException {
1933
        return this.findFirst(filter, sortBy, true);
1934
    }
1935

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

    
1947
    @Override
1948
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
1949
        return this.findFirst(filter, sortBy, true);
1950
    }
1951

    
1952
    @Override
1953
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
1954
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1955
        return findFirst(query);
1956
    }
1957
    
1958
    @Override
1959
    public Feature findFirst(FeatureQuery query) throws DataException {
1960
        final MutableObject<Feature> feature = new MutableObject<>();
1961
        try {
1962
            this.accept(new Visitor() {
1963
                @Override
1964
                public void visit(Object obj) throws VisitCanceledException, BaseException {
1965
                    feature.setValue((Feature) obj);
1966
                    throw new VisitCanceledException();
1967
                }
1968
            }, query);
1969
        } catch(VisitCanceledException ex) {
1970

    
1971
        } catch(DataException ex) {
1972
            throw ex;
1973
        } catch(Exception ex) {
1974
            throw new RuntimeException("", ex);
1975
        }
1976
        return feature.getValue();
1977
    }
1978

    
1979
    @Override
1980
    public void accept(Visitor visitor) throws BaseException {
1981
        this.accept(visitor, null);
1982
    }
1983

    
1984
    @Override
1985
    public void accept(Visitor visitor, DataQuery dataQuery)
1986
        throws BaseException {
1987
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
1988
        try {
1989
            set.accept(visitor);
1990
        } finally {
1991
            set.dispose();
1992
        }
1993
    }
1994

    
1995
    public FeatureType getFeatureType(FeatureQuery featureQuery)
1996
        throws DataException {
1997
        DefaultFeatureType fType =
1998
            (DefaultFeatureType) this.getFeatureType(featureQuery
1999
                .getFeatureTypeId());
2000
        if( featureQuery.hasAttributeNames() || 
2001
            featureQuery.hasConstantsAttributeNames() ||
2002
            fType.hasRequiredFields()    
2003
            ) {
2004
            return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames() );
2005
        }
2006
        return fType;
2007
    }
2008

    
2009
    @Override
2010
    public void getFeatureSet(Observer observer) throws DataException {
2011
        checkNotInAppendMode();
2012
        this.getFeatureSet(null, observer);
2013
    }
2014

    
2015
    @Override
2016
    public void getFeatureSet(FeatureQuery query, Observer observer)
2017
        throws DataException {
2018
        class LoadInBackGround implements Runnable {
2019

    
2020
            private final FeatureStore store;
2021
            private final FeatureQuery query;
2022
            private final Observer observer;
2023

    
2024
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2025
                Observer observer) {
2026
                this.store = store;
2027
                this.query = query;
2028
                this.observer = observer;
2029
            }
2030

    
2031
            void notify(FeatureStoreNotification theNotification) {
2032
                observer.update(store, theNotification);
2033
            }
2034

    
2035
            @Override
2036
            public void run() {
2037
                FeatureSet set = null;
2038
                try {
2039
                    set = store.getFeatureSet(query);
2040
                    notify(new DefaultFeatureStoreNotification(store,
2041
                        FeatureStoreNotification.LOAD_FINISHED, set));
2042
                } catch (Exception e) {
2043
                    notify(new DefaultFeatureStoreNotification(store,
2044
                        FeatureStoreNotification.LOAD_FINISHED, e));
2045
                } finally {
2046
                    dispose(set);
2047
                }
2048
            }
2049
        }
2050

    
2051
        checkNotInAppendMode();
2052
        if (query == null) {
2053
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2054
        }
2055
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2056
        Thread thread = new Thread(task, "Load Feature Set in background");
2057
        thread.start();
2058
    }
2059

    
2060
    @Override
2061
    public Feature getFeatureByReference(FeatureReference reference)
2062
        throws DataException {
2063
        checkNotInAppendMode();
2064
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
2065
        FeatureType featureType;
2066
        if (ref.getFeatureTypeId() == null) {
2067
            featureType = this.getDefaultFeatureType();
2068
        } else {
2069
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2070
        }
2071
        return this.getFeatureByReference(reference, featureType);
2072
    }
2073

    
2074
    @Override
2075
    public Feature getFeatureByReference(FeatureReference reference,
2076
        FeatureType featureType) throws DataException {
2077
        checkNotInAppendMode();
2078
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2079
        if (this.mode == MODE_FULLEDIT) {
2080
            Feature f = featureManager.get(reference, this, featureType);
2081
            if (f != null) {
2082
                return f;
2083
            }
2084
        }
2085

    
2086
        FeatureType sourceFeatureType = featureType;
2087
        if (!this.transforms.isEmpty()) {
2088
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2089
        }
2090
        // TODO comprobar que el id es de este store
2091

    
2092
        DefaultFeature feature =
2093
            new DefaultFeature(this,
2094
                this.provider.getFeatureProviderByReference(
2095
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2096

    
2097
        if (!this.transforms.isEmpty()) {
2098
            return this.transforms.applyTransform(feature, featureType);
2099
        }
2100
        return feature;
2101
    }
2102

    
2103
    //
2104
    // ====================================================================
2105
    // Gestion de features
2106
    //
2107

    
2108
    private FeatureType fixFeatureType(DefaultFeatureType type)
2109
        throws DataException {
2110
        FeatureType original = this.getDefaultFeatureType();
2111

    
2112
        if ((type == null) || type.equals(original)) {
2113
            return original;
2114
        } else {
2115
            if (!type.isSubtypeOf(original)) {
2116
                Iterator iter = this.getFeatureTypes().iterator();
2117
                FeatureType tmpType;
2118
                boolean found = false;
2119
                while (iter.hasNext()) {
2120
                    tmpType = (FeatureType) iter.next();
2121
                    if (type.equals(tmpType)) {
2122
                        return type;
2123

    
2124
                    } else
2125
                        if (type.isSubtypeOf(tmpType)) {
2126
                            found = true;
2127
                            original = tmpType;
2128
                            break;
2129
                        }
2130

    
2131
                }
2132
                if (!found) {
2133
                    throw new IllegalFeatureTypeException(getName());
2134
                }
2135
            }
2136
        }
2137

    
2138
        // Checks that type has all fields of pk
2139
        // else add the missing attributes at the end.
2140
        if (!original.hasOID()) {
2141
            // Gets original pk attributes
2142
            DefaultEditableFeatureType edOriginal =
2143
                (DefaultEditableFeatureType) original.getEditable();
2144
            FeatureAttributeDescriptor orgAttr;
2145
            Iterator edOriginalIter = edOriginal.iterator();
2146
            while (edOriginalIter.hasNext()) {
2147
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2148
                if (!orgAttr.isPrimaryKey()) {
2149
                    edOriginalIter.remove();
2150
                }
2151
            }
2152

    
2153
            // Checks if all pk attributes are in type
2154
            Iterator typeIterator;
2155
            edOriginalIter = edOriginal.iterator();
2156
            FeatureAttributeDescriptor attr;
2157
            while (edOriginalIter.hasNext()) {
2158
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2159
                typeIterator = type.iterator();
2160
                while (typeIterator.hasNext()) {
2161
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2162
                    if (attr.getName().equals(orgAttr.getName())) {
2163
                        edOriginalIter.remove();
2164
                        break;
2165
                    }
2166
                }
2167
            }
2168

    
2169
            // add missing pk attributes if any
2170
            if (edOriginal.size() > 0) {
2171
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2172
                DefaultEditableFeatureType edType =
2173
                    (DefaultEditableFeatureType) original.getEditable();
2174
                edType.clear();
2175
                edType.addAll(type);
2176
                edType.addAll(edOriginal);
2177
                if (!isEditable) {
2178
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2179
                }
2180
            }
2181

    
2182
        }
2183

    
2184
        return type;
2185
    }
2186

    
2187
    @Override
2188
    public void validateFeatures(int mode) throws DataException {
2189
        FeatureSet collection = null;
2190
        DisposableIterator iter = null;
2191
        try {
2192
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2193
            if( rules==null || rules.isEmpty() ) {
2194
                return;
2195
            }
2196
            checkNotInAppendMode();
2197
            collection = this.getFeatureSet();
2198
            iter = collection.fastIterator();
2199
            long previousVersionOfUpdate = currentVersionOfUpdate();
2200
            while (iter.hasNext()) {
2201
                ((DefaultFeature) iter.next()).validate(mode);
2202
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2203
                    throw new ConcurrentDataModificationException(getName());
2204
                }
2205
            }
2206
        } catch (Exception e) {
2207
            throw new ValidateFeaturesException(e, getName());
2208
        } finally {
2209
            DisposeUtils.disposeQuietly(iter);
2210
            DisposeUtils.disposeQuietly(collection);
2211
        }
2212
    }
2213

    
2214
    @Override
2215
    public FeatureType getDefaultFeatureType() throws DataException {
2216
        try {
2217

    
2218
            if (isEditing()) {
2219
                FeatureType auxFeatureType =
2220
                    featureTypeManager.getType(defaultFeatureType.getId());
2221
                if (auxFeatureType != null) {
2222
                    return avoidEditable(auxFeatureType);
2223
                }
2224
            }
2225
            FeatureType type = this.transforms.getDefaultFeatureType();
2226
                if (type != null) {
2227
                return avoidEditable(type);
2228
                }
2229

    
2230
            return avoidEditable(defaultFeatureType);
2231

    
2232
        } catch (Exception e) {
2233
            throw new GetFeatureTypeException(e, getName());
2234
        }
2235
    }
2236
    
2237
    private FeatureType avoidEditable(FeatureType ft) {
2238
        if (ft instanceof EditableFeatureType) {
2239
            return ((EditableFeatureType) ft).getNotEditableCopy();
2240
        } else {
2241
            return ft;
2242
        }
2243
    }
2244

    
2245
    @Override
2246
    public FeatureType getFeatureType(String featureTypeId)
2247
        throws DataException {
2248
        if (featureTypeId == null) {
2249
            return this.getDefaultFeatureType();
2250
        }
2251
        try {
2252
            if (isEditing()) {
2253
                FeatureType auxFeatureType =
2254
                    featureTypeManager.getType(featureTypeId);
2255
                if (auxFeatureType != null) {
2256
                    return auxFeatureType;
2257
                }
2258
            }
2259
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2260
            if (type != null) {
2261
                return type;
2262
            }
2263
            Iterator iter = this.featureTypes.iterator();
2264
            while (iter.hasNext()) {
2265
                type = (FeatureType) iter.next();
2266
                if (type.getId().equals(featureTypeId)) {
2267
                    return type;
2268
                }
2269
            }
2270
            return null;
2271
        } catch (Exception e) {
2272
            throw new GetFeatureTypeException(e, getName());
2273
        }
2274
    }
2275

    
2276
    public FeatureType getProviderDefaultFeatureType() {
2277
        return defaultFeatureType;
2278
    }
2279

    
2280
    @Override
2281
    public List getFeatureTypes() throws DataException {
2282
        try {
2283
            List types;
2284
            if (isEditing()) {
2285
                types = new ArrayList();
2286
                Iterator it = featureTypes.iterator();
2287
                while (it.hasNext()) {
2288
                    FeatureType type = (FeatureType) it.next();
2289
                    FeatureType typeaux =
2290
                        featureTypeManager.getType(type.getId());
2291
                    if (typeaux != null) {
2292
                        types.add(typeaux);
2293
                    } else {
2294
                        types.add(type);
2295
                    }
2296
                }
2297
                it = featureTypeManager.newsIterator();
2298
                while (it.hasNext()) {
2299
                    FeatureType type = (FeatureType) it.next();
2300
                    types.add(type);
2301
                }
2302
            } else {
2303
                types = this.transforms.getFeatureTypes();
2304
                if (types == null) {
2305
                    types = featureTypes;
2306
                }
2307
            }
2308
            return Collections.unmodifiableList(types);
2309
        } catch (Exception e) {
2310
            throw new GetFeatureTypeException(e, getName());
2311
        }
2312
    }
2313

    
2314
    public List getProviderFeatureTypes() throws DataException {
2315
        return Collections.unmodifiableList(this.featureTypes);
2316
    }
2317

    
2318
    @Override
2319
    public Feature createFeature(FeatureProvider data) throws DataException {
2320
        DefaultFeature feature = new DefaultFeature(this, data);
2321
        return feature;
2322
    }
2323

    
2324
    public Feature createFeature(FeatureProvider data, FeatureType type)
2325
        throws DataException {
2326
        // FIXME: falta por implementar
2327
        // Comprobar si es un subtipo del feature de data
2328
        // y construir un feature usando el subtipo.
2329
        // Probablemente requiera generar una copia del data.
2330
        throw new NotYetImplemented();
2331
    }
2332

    
2333
    @Override
2334
    public EditableFeature createNewFeature(FeatureType type,
2335
        Feature defaultValues) throws DataException {
2336
        try {
2337
            FeatureProvider data = createNewFeatureProvider(type);
2338
            DefaultEditableFeature feature =
2339
                new DefaultEditableFeature(this, data);
2340
            feature.initializeValues(defaultValues);
2341
            data.setNew(true);
2342

    
2343
            return feature;
2344
        } catch (Exception e) {
2345
            throw new CreateFeatureException(e, getName());
2346
        }
2347
    }
2348

    
2349
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2350
        throws DataException {
2351
        type = this.fixFeatureType((DefaultFeatureType) type);
2352
        FeatureProvider data = this.provider.createFeatureProvider(type);
2353
        data.setNew(true);
2354
        if (type.hasOID() && (data.getOID() == null)) {
2355
            data.setOID(this.provider.createNewOID());
2356
        } else {
2357
            data.setOID(this.getTemporalOID());
2358
        }
2359
        return data;
2360

    
2361
    }
2362

    
2363
    @Override
2364
    public EditableFeature createNewFeature(FeatureType type,
2365
        boolean defaultValues) throws DataException {
2366
        try {
2367
            FeatureProvider data = createNewFeatureProvider(type);
2368
            DefaultEditableFeature feature =
2369
                new DefaultEditableFeature(this, data);
2370
            if (defaultValues) {
2371
                feature.initializeValues();
2372
            }
2373
            return feature;
2374
        } catch (Exception e) {
2375
            throw new CreateFeatureException(e, getName());
2376
        }
2377
    }
2378

    
2379
    @Override
2380
    public EditableFeature createNewFeature(boolean defaultValues)
2381
        throws DataException {
2382
        return this.createNewFeature(this.getDefaultFeatureType(),
2383
            defaultValues);
2384
    }
2385

    
2386
    @Override
2387
    public EditableFeature createNewFeature() throws DataException {
2388
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2389
    }
2390

    
2391
    @Override
2392
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2393
        FeatureType ft = this.getDefaultFeatureType();
2394
        EditableFeature f = this.createNewFeature(ft, false);
2395
                for( FeatureAttributeDescriptor desc : ft ) {
2396
                        try {
2397
                                f.set(desc.getName(), defaultValues.get(desc.getName()));
2398
                        } catch(Throwable th) {
2399
                                // Ignore
2400
                        }
2401
                }
2402
        return f;
2403
    }
2404

    
2405
    @Override
2406
    public EditableFeatureType createFeatureType() {
2407
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2408
        return ftype;
2409
    }
2410

    
2411
    @Override
2412
    public EditableFeatureType createFeatureType(String id) {
2413
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2414
        return ftype;
2415
    }
2416

    
2417
    //
2418
    // ====================================================================
2419
    // Index related methods
2420
    //
2421

    
2422
    @Override
2423
    public FeatureIndexes getIndexes() {
2424
        return this.indexes;
2425
    }
2426

    
2427
    @Override
2428
    public FeatureIndex createIndex(FeatureType featureType,
2429
        String attributeName, String indexName) throws DataException {
2430
        return createIndex(null, featureType, attributeName, indexName);
2431
    }
2432

    
2433
    @Override
2434
    public FeatureIndex createIndex(String indexTypeName,
2435
        FeatureType featureType, String attributeName, String indexName)
2436
        throws DataException {
2437

    
2438
        return createIndex(indexTypeName, featureType, attributeName,
2439
            indexName, false, null);
2440
    }
2441

    
2442
    @Override
2443
    public FeatureIndex createIndex(FeatureType featureType,
2444
        String attributeName, String indexName, Observer observer)
2445
        throws DataException {
2446
        return createIndex(null, featureType, attributeName, indexName,
2447
            observer);
2448
    }
2449

    
2450
    @Override
2451
    public FeatureIndex createIndex(String indexTypeName,
2452
        FeatureType featureType, String attributeName, String indexName,
2453
        final Observer observer) throws DataException {
2454

    
2455
        return createIndex(indexTypeName, featureType, attributeName,
2456
            indexName, true, observer);
2457
    }
2458

    
2459
    private FeatureIndex createIndex(String indexTypeName,
2460
        FeatureType featureType, String attributeName, String indexName,
2461
        boolean background, final Observer observer) throws DataException {
2462

    
2463
        checkNotInAppendMode();
2464
        FeatureIndexProviderServices index;
2465
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2466
                featureType, indexName,
2467
                featureType.getAttributeDescriptor(attributeName));
2468

    
2469
        try {
2470
            index.fill(background, observer);
2471
        } catch (FeatureIndexException e) {
2472
            throw new InitializeException(index.getName(), e);
2473
        }
2474

    
2475
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2476
        return index;
2477
    }
2478

    
2479
    //
2480
    // ====================================================================
2481
    // Transforms related methods
2482
    //
2483

    
2484
    @Override
2485
    public FeatureStoreTransforms getTransforms() {
2486
        return this.transforms;
2487
    }
2488

    
2489
    @Override
2490
    public FeatureQuery createFeatureQuery() {
2491
        return new DefaultFeatureQuery();
2492
    }
2493
    
2494
    private FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
2495
        FeatureQuery query = null;
2496
        if( filter!=null ) {
2497
            query = this.createFeatureQuery();
2498
            query.setFilter(filter);
2499
        }
2500
        if( !StringUtils.isEmpty(sortBy) ) {
2501
            if( query == null ) {
2502
                query = this.createFeatureQuery();
2503
            }
2504
            query.getOrder().add(sortBy, asc);
2505
        }
2506
        if( query != null ) {
2507
            query.retrievesAllAttributes();
2508
        }
2509
        return query;
2510
    }
2511
    
2512
    private FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
2513
        FeatureQuery query = null;
2514
        if( !StringUtils.isEmpty(filter) ) {
2515
            query = this.createFeatureQuery();
2516
            query.setFilter(filter);
2517
        }
2518
        if( !StringUtils.isEmpty(sortBy) ) {
2519
            if( query == null ) {
2520
                query = this.createFeatureQuery();
2521
            }
2522
            query.getOrder().add(sortBy, asc);
2523
        }
2524
        if( query != null ) {
2525
            query.retrievesAllAttributes();
2526
        }
2527
        return query;
2528
    }
2529
    
2530
    @Override
2531
    public DataQuery createQuery() {
2532
        return createFeatureQuery();
2533
    }
2534

    
2535
    //
2536
    // ====================================================================
2537
    // UndoRedo related methods
2538
    //
2539

    
2540
    @Override
2541
    public boolean canRedo() {
2542
        return commands.canRedo();
2543
    }
2544

    
2545
    @Override
2546
    public boolean canUndo() {
2547
        return commands.canUndo();
2548
    }
2549

    
2550
    @Override
2551
    public void redo(int num) throws RedoException {
2552
        for (int i = 0; i < num; i++) {
2553
            redo();
2554
        }
2555
    }
2556

    
2557
    @Override
2558
    public void undo(int num) throws UndoException {
2559
        for (int i = 0; i < num; i++) {
2560
            undo();
2561
        }
2562
    }
2563

    
2564
    //
2565
    // ====================================================================
2566
    // Metadata related methods
2567
    //
2568

    
2569
    @Override
2570
    public Object getMetadataID() {
2571
        return this.provider.getSourceId();
2572
    }
2573

    
2574
    @Override
2575
    public void delegate(DynObject dynObject) {
2576
        this.metadata.delegate(dynObject);
2577
    }
2578

    
2579
    @Override
2580
    public DynClass getDynClass() {
2581
        return this.metadata.getDynClass();
2582
    }
2583

    
2584
    @Override
2585
    public Object getDynValue(String name) throws DynFieldNotFoundException {
2586
        try {
2587
            if (this.transforms.hasDynValue(name)) {
2588
                return this.transforms.getDynValue(name);
2589
            }
2590
            if (this.metadata.hasDynValue(name)) {
2591
                return this.metadata.getDynValue(name);
2592
            }
2593
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2594
                return this.provider.getProviderName();
2595
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2596
                return this.provider.getSourceId();
2597
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2598
                try {
2599
                    return this.getDefaultFeatureType();
2600
                } catch (DataException e) {
2601
                    return null;
2602
                }
2603
            }
2604
            return this.metadata.getDynValue(name);
2605
        } catch(Exception ex ) {
2606
            LOG.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
2607
            return null;
2608
        }
2609
    }
2610

    
2611
    @Override
2612
    public boolean hasDynValue(String name) {
2613
        if (this.transforms.hasDynValue(name)) {
2614
            return true;
2615
        }
2616
        return this.metadata.hasDynValue(name);
2617
    }
2618

    
2619
    @Override
2620
    public boolean hasDynMethod(String name) {
2621
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2622
    }
2623

    
2624
    @Override
2625
    public void implement(DynClass dynClass) {
2626
        this.metadata.implement(dynClass);
2627
    }
2628

    
2629
    @Override
2630
    public Object invokeDynMethod(String name, Object[] args)
2631
        throws DynMethodException {
2632
        return this.metadata.invokeDynMethod(this, name, args);
2633
    }
2634

    
2635
    @Override
2636
    public Object invokeDynMethod(int code, Object[] args)
2637
        throws DynMethodException {
2638
        return this.metadata.invokeDynMethod(this, code, args);
2639
    }
2640

    
2641
    @Override
2642
    public void setDynValue(String name, Object value)
2643
        throws DynFieldNotFoundException {
2644
                if( this.transforms.hasDynValue(name) ) {
2645
                        this.transforms.setDynValue(name, value);
2646
                        return;
2647
                }
2648
        this.metadata.setDynValue(name, value);
2649

    
2650
    }
2651

    
2652
    /*
2653
     * (non-Javadoc)
2654
     *
2655
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2656
     */
2657
    @Override
2658
    public Set getMetadataChildren() {
2659
        return this.metadataChildren;
2660
    }
2661

    
2662
    /*
2663
     * (non-Javadoc)
2664
     *
2665
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2666
     */
2667
    @Override
2668
    public String getMetadataName() {
2669
        return this.provider.getProviderName();
2670
    }
2671

    
2672
    public FeatureTypeManager getFeatureTypeManager() {
2673
        return this.featureTypeManager;
2674
    }
2675

    
2676
    @Override
2677
    public long getFeatureCount() throws DataException {
2678
        if (featureCount == null) {
2679
            featureCount = this.provider.getFeatureCount();
2680
        }
2681
        if (this.isEditing()) {
2682
            if(this.isAppending()) {
2683
                try{
2684
                    throw new IllegalStateException();
2685
                } catch(IllegalStateException e) {
2686
                    LOG.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
2687
                }
2688
                return -1;
2689
            } else {
2690
                return featureCount
2691
                    + this.featureManager.getDeltaSize();
2692
            }
2693
        }
2694
        return featureCount;
2695
    }
2696

    
2697
    private Long getTemporalOID() {
2698
        return this.temporalOid++;
2699
    }
2700

    
2701
    @Override
2702
    public FeatureType getProviderFeatureType(String featureTypeId) {
2703
        if (featureTypeId == null) {
2704
            return this.defaultFeatureType;
2705
        }
2706
        FeatureType type;
2707
        Iterator iter = this.featureTypes.iterator();
2708
        while (iter.hasNext()) {
2709
            type = (FeatureType) iter.next();
2710
            if (type.getId().equals(featureTypeId)) {
2711
                return type;
2712
            }
2713
        }
2714
        return null;
2715
    }
2716

    
2717
    @Override
2718
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2719
        return ((DefaultFeature) feature).getData();
2720
    }
2721

    
2722
    @Override
2723
    public DataStore getStore() {
2724
        return this;
2725
    }
2726

    
2727
    @Override
2728
    public FeatureStore getFeatureStore() {
2729
        return this;
2730
    }
2731

    
2732
    @Override
2733
    public void createCache(String name, DynObject parameters)
2734
        throws DataException {
2735
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2736
        if (cache == null) {
2737
            throw new CreateException("FeaureCacheProvider", null);
2738
        }
2739
        cache.apply(this, provider);
2740
        provider = cache;
2741

    
2742
        featureCount = null;
2743
    }
2744

    
2745
    @Override
2746
    public FeatureCache getCache() {
2747
        return cache;
2748
    }
2749

    
2750
    @Override
2751
    public void clear() {
2752
        if (metadata != null) {
2753
            metadata.clear();
2754
        }
2755
    }
2756

    
2757
    @Override
2758
    public String getName() {
2759
        if( this.provider != null ) {
2760
            return this.provider.getName();
2761
        }
2762
        if( this.parameters instanceof HasAFile ) {
2763
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
2764
        }
2765
        return "unknow";
2766
    }
2767

    
2768
    @Override
2769
    public String getFullName() {
2770
        try {
2771
            if( this.provider!=null ) {
2772
                return this.provider.getFullName();
2773
            }
2774
            if( this.parameters instanceof HasAFile ) {
2775
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
2776
            }
2777
            return null;
2778
        } catch(Throwable th) {
2779
            return null;
2780
        }
2781
    }
2782

    
2783
    @Override
2784
    public String getProviderName() {
2785
        if( this.provider!=null ) {
2786
            return this.provider.getProviderName();
2787
        }
2788
        if( this.parameters != null ) {
2789
            return this.parameters.getDataStoreName();
2790
        }
2791
        return null;
2792

    
2793
    }
2794

    
2795
    @Override
2796
    public boolean isKnownEnvelope() {
2797
        return this.provider.isKnownEnvelope();
2798
    }
2799

    
2800
    @Override
2801
    public boolean hasRetrievedFeaturesLimit() {
2802
        return this.provider.hasRetrievedFeaturesLimit();
2803
    }
2804

    
2805
    @Override
2806
    public int getRetrievedFeaturesLimit() {
2807
        return this.provider.getRetrievedFeaturesLimit();
2808
    }
2809

    
2810
    @Override
2811
    public Interval getInterval() {
2812
        if( this.timeSupport!=null ) {
2813
            return this.timeSupport.getInterval();
2814
        }
2815
        try {
2816
            FeatureType type = this.getDefaultFeatureType();
2817
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
2818
            if( attr!=null ) {
2819
                Interval interval = attr.getInterval();
2820
                if( interval!=null ) {
2821
                    return interval;
2822
                }
2823
            }
2824
        } catch (DataException ex) {
2825
        }
2826
        return this.provider.getInterval();
2827
    }
2828

    
2829
    @Override
2830
    public Collection getTimes() {
2831
        if( this.timeSupport!=null ) {
2832
            return this.timeSupport.getTimes();
2833
        }
2834
        return this.provider.getTimes();
2835
    }
2836

    
2837
    @Override
2838
    public Collection getTimes(Interval interval) {
2839
        if( this.timeSupport!=null ) {
2840
            return this.timeSupport.getTimes(interval);
2841
        }
2842
        return this.provider.getTimes(interval);
2843
    }
2844

    
2845
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
2846
        if( this.isEditing() ) {
2847
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
2848
        }
2849
        if( !this.transforms.isEmpty() ) {
2850
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
2851
        }
2852
        FeatureType ft = this.defaultFeatureType;
2853
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
2854
        if( attr == null ) {
2855
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
2856
        }
2857
        EditableFeatureType eft = ft.getEditable();
2858
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
2859
        if( attr != null ) {
2860
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
2861
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
2862
            }
2863
            eft.remove(attr.getName());
2864
        }
2865
        EditableFeatureAttributeDescriptor attrTime = eft.add(
2866
            timeSupport.getAttributeName(), 
2867
            timeSupport.getDataType()
2868
        );
2869
        attrTime.setIsTime(true);
2870
        attrTime.setFeatureAttributeEmulator(timeSupport);
2871
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
2872
        this.defaultFeatureType = eft.getNotEditableCopy();
2873
        
2874
        this.timeSupport = timeSupport;
2875
    }
2876

    
2877
    @Override
2878
    @SuppressWarnings("CloneDoesntCallSuperClone")
2879
    public Object clone() throws CloneNotSupportedException {
2880

    
2881
        DataStoreParameters dsp = getParameters();
2882

    
2883
        DefaultFeatureStore cloned_store = null;
2884

    
2885
        try {
2886
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2887
                openStore(this.getProviderName(), dsp);
2888
            if (transforms != null) {
2889
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2890
                cloned_store.transforms.setStoreForClone(cloned_store);
2891
            }
2892
        } catch (Exception e) {
2893
            throw new CloneException(e);
2894
        }
2895
        return cloned_store;
2896

    
2897
    }
2898

    
2899
    @Override
2900
    public Feature getFeature(DynObject dynobject) {
2901
        if (dynobject instanceof DynObjectFeatureFacade){
2902
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2903
            return f;
2904
        }
2905
        return null;
2906
    }
2907

    
2908
    @Override
2909
    public Iterator iterator() {
2910
        try {
2911
            return this.getFeatureSet().fastIterator();
2912
        } catch (DataException ex) {
2913
            throw new RuntimeException(ex);
2914
        }
2915
    }
2916

    
2917
    @Override
2918
    public ExpressionBuilder createExpressionBuilder() {
2919
        ExpressionBuilder builder;
2920
        builder = ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2921
        return builder;
2922
    }
2923

    
2924
    @Override
2925
    public ExpressionBuilder createExpression() {
2926
        return createExpressionBuilder();
2927
    }
2928

    
2929
    public FeatureSet features() throws DataException {
2930
        // This is to avoid jython to create a property with this name
2931
        // to access method getFeatures.
2932
        return this.getFeatureSet();
2933
    }
2934

    
2935
    @Override
2936
    public DataStoreProviderFactory getProviderFactory() {
2937
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
2938
        return factory;
2939
    }
2940

    
2941
    @Override
2942
    public void useCache(String providerName, DynObject parameters) throws DataException {
2943
        throw new UnsupportedOperationException();
2944
    }
2945

    
2946
    @Override
2947
    public boolean isBroken() {
2948
        return this.state.isBroken();
2949
    }
2950

    
2951
    @Override
2952
    public Throwable getBreakingsCause() {
2953
            return this.state.getBreakingsCause();
2954
    }
2955

    
2956
    @Override
2957
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
2958
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
2959
      if( !factory.supportNumericOID() ) {
2960
          return null;
2961
      }
2962
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
2963
      return wrappedIndex;
2964
  }
2965

    
2966
    @Override
2967
    public FeatureReference getFeatureReference(String code) {
2968
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
2969
        return featureReference;
2970
    }
2971

    
2972
    @Override
2973
    public long getPendingChangesCount() {
2974
        if( this.featureManager==null ) {
2975
            return 0;
2976
        }
2977
        return this.featureManager.getPendingChangesCount();
2978
    }
2979

    
2980
    @Override
2981
    public ResourcesStorage getResourcesStorage() {
2982
        try {
2983
            DataServerExplorer explorer = this.getExplorer();
2984
            if( explorer==null ) {
2985
                return null;
2986
            }
2987
            return this.getExplorer().getResourcesStorage(this);
2988
        } catch (Exception ex) {
2989
            LOG.warn("Can't create resources storage",ex);
2990
            return null;
2991
        }
2992
    }
2993

    
2994
    @Override
2995
    public StoresRepository getStoresRepository() {
2996
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
2997
        StoresRepository repository = new StoresRepository() {
2998
            @Override
2999
            public void add(String name, DataStoreParameters parameters) {
3000
                mainRepository.add(name, parameters);
3001
            }
3002

    
3003
            @Override
3004
            public void remove(String name) {
3005
                mainRepository.remove(name);
3006
            }
3007

    
3008
            @Override
3009
            public DataStore get(String key) {
3010
                DataStore store = getChildren().get(key);
3011
                if( store != null ) {
3012
                    return store;
3013
                }
3014
                return mainRepository.get(key);
3015
            }
3016

    
3017
            @Override
3018
            public boolean isEmpty() {
3019
                return getChildren().isEmpty() && mainRepository.isEmpty();
3020
            }
3021

    
3022
            @Override
3023
            public boolean containsKey(String key) {
3024
                return getChildren().containsKey(key) || mainRepository.containsKey(key);
3025
            }
3026

    
3027
            @Override
3028
            public Map<String, DataStore> toMap() {
3029
                return null;
3030
            }
3031

    
3032
            @Override
3033
            public int size() {
3034
                return getChildren().size()+mainRepository.size();
3035
            }
3036

    
3037
            @Override
3038
            public UnmodifiableBasicSet<String> keySet() {
3039
                UnmodifiableBasicMap<String, DataStore> children = getChildren();
3040
                if( children.isEmpty() ) {
3041
                    return mainRepository.keySet();
3042
                }
3043
                return new UnmodifiableBasicSetChained<>(
3044
                        children.keySet(), 
3045
                        mainRepository.keySet()
3046
                );
3047
            }
3048

    
3049
            @Override
3050
            public Iterator<DataStore> iterator() {
3051
                final Iterator<String> it = this.keySet().iterator();
3052
                return new Iterator<DataStore>() {
3053
                    @Override
3054
                    public boolean hasNext() {
3055
                        return it.hasNext();
3056
                    }
3057

    
3058
                    @Override
3059
                    public DataStore next() {
3060
                        String name = it.next();
3061
                        return get(name);
3062
                    }
3063
                };
3064
            }
3065
        };
3066
        return repository;
3067
    }
3068

    
3069
    @Override
3070
    public Feature getSampleFeature() {
3071
            Feature sampleFeature;
3072
            try {
3073
                FeatureSelection theSelection = this.getFeatureSelection();
3074
                if( theSelection!=null && !theSelection.isEmpty() ) {
3075
                    sampleFeature = theSelection.first();
3076
                } else {
3077
                    sampleFeature = this.first();
3078
                }
3079
                if( sampleFeature==null ) {
3080
                    sampleFeature = this.createNewFeature();
3081
                }
3082
            } catch (DataException ex) {
3083
                return null;
3084
            }
3085
            return sampleFeature;
3086
    }
3087
        
3088
}