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

History | View | Annotate | Download (103 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.DALResourcesStorage;
132
import org.gvsig.fmap.dal.impl.DefaultDataManager;
133
import org.gvsig.fmap.dal.resource.Resource;
134
import org.gvsig.fmap.dal.spi.DataStoreInitializer2;
135
import org.gvsig.fmap.dal.spi.DataStoreProvider;
136
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
137
import org.gvsig.fmap.geom.Geometry;
138
import org.gvsig.fmap.geom.SpatialIndex;
139
import org.gvsig.fmap.geom.primitive.Envelope;
140
import org.gvsig.metadata.MetadataLocator;
141
import org.gvsig.metadata.MetadataManager;
142
import org.gvsig.metadata.exceptions.MetadataException;
143
import org.gvsig.timesupport.Interval;
144
import org.gvsig.tools.ToolsLocator;
145
import org.gvsig.tools.dispose.DisposableIterator;
146
import org.gvsig.tools.dispose.DisposeUtils;
147
import org.gvsig.tools.dispose.impl.AbstractDisposable;
148
import org.gvsig.tools.dynobject.DelegatedDynObject;
149
import org.gvsig.tools.dynobject.DynClass;
150
import org.gvsig.tools.dynobject.DynObject;
151
import org.gvsig.tools.dynobject.DynObjectManager;
152
import org.gvsig.tools.dynobject.DynObject_v2;
153
import org.gvsig.tools.dynobject.DynStruct;
154
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
155
import org.gvsig.tools.dynobject.exception.DynMethodException;
156
import org.gvsig.tools.exception.BaseException;
157
import org.gvsig.tools.exception.NotYetImplemented;
158
import org.gvsig.tools.identitymanagement.SimpleIdentityManager;
159
import org.gvsig.tools.observer.Observable;
160
import org.gvsig.tools.observer.Observer;
161
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
162
import org.gvsig.tools.persistence.PersistenceManager;
163
import org.gvsig.tools.persistence.Persistent;
164
import org.gvsig.tools.persistence.PersistentState;
165
import org.gvsig.tools.persistence.exception.PersistenceException;
166
import org.gvsig.tools.undo.RedoException;
167
import org.gvsig.tools.undo.UndoException;
168
import org.gvsig.tools.undo.command.Command;
169
import org.gvsig.tools.util.HasAFile;
170
import org.gvsig.tools.util.ResourcesStorage;
171
import org.gvsig.tools.util.UnmodifiableBasicMap;
172
import org.gvsig.tools.util.UnmodifiableBasicSet;
173
import org.gvsig.tools.util.UnmodifiableBasicSetChained;
174
import org.gvsig.tools.visitor.VisitCanceledException;
175
import org.gvsig.tools.visitor.Visitor;
176

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

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

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

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

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

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

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

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

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

    
213
    private DefaultDataManager dataManager = null;
214

    
215
    private FeatureStoreProvider provider = null;
216

    
217
    private DefaultFeatureIndexes indexes;
218

    
219
    private DefaultFeatureStoreTransforms transforms;
220

    
221
    DelegatedDynObject metadata;
222

    
223
    private Set metadataChildren;
224

    
225
    private Long featureCount = null;
226

    
227
    private long temporalOid = 0;
228

    
229
    private FeatureCacheProvider cache;
230

    
231
    StateInformation state;
232

    
233
    FeatureStoreTimeSupport timeSupport;
234

    
235

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

    
238
        private static final long serialVersionUID = 4109026189635185666L;
239

    
240
        private boolean broken;
241
        private Throwable breakingsCause;
242

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

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

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

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

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

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

    
275

    
276

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

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

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

    
294
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
295

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

    
301
        this.dataManager = (DefaultDataManager) dataManager;
302

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

    
311
    }
312

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
586
        }
587

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

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

    
595
    }
596

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

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

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

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

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

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

    
708
                    }
709

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

    
715

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
909
    }
910

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

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

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

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

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

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

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

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

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

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

    
974
    }
975

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

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

    
985
    }
986

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

    
991
    }
992

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

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

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

    
1011
    }
1012

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

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

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

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

    
1043
    //
1044
    // ====================================================================
1045
    // Edicion
1046
    //
1047

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

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

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

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

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

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

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

    
1088
        }
1089

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

    
1094
        featureCount = null;
1095

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1280
    private static EditableFeature lastChangedFeature = null;
1281

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

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

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

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

    
1320
        waitForIndexes();
1321

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

    
1334

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1699
        case MODE_APPEND:
1700
                return true;
1701

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1953
    @Override
1954
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
1955
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
1956
        return findFirst(query);
1957
    }
1958
    
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
        return new DALResourcesStorage(this);
2983
    }
2984

    
2985
    @Override
2986
    public StoresRepository getStoresRepository() {
2987
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
2988
        StoresRepository repository = new StoresRepository() {
2989
            @Override
2990
            public void add(String name, DataStoreParameters parameters) {
2991
                mainRepository.add(name, parameters);
2992
            }
2993

    
2994
            @Override
2995
            public void remove(String name) {
2996
                mainRepository.remove(name);
2997
            }
2998

    
2999
            @Override
3000
            public DataStore get(String key) {
3001
                DataStore store = getChildren().get(key);
3002
                if( store != null ) {
3003
                    return store;
3004
                }
3005
                return mainRepository.get(key);
3006
            }
3007

    
3008
            @Override
3009
            public boolean isEmpty() {
3010
                return getChildren().isEmpty() && mainRepository.isEmpty();
3011
            }
3012

    
3013
            @Override
3014
            public boolean containsKey(String key) {
3015
                return getChildren().containsKey(key) || mainRepository.containsKey(key);
3016
            }
3017

    
3018
            @Override
3019
            public Map<String, DataStore> toMap() {
3020
                return null;
3021
            }
3022

    
3023
            @Override
3024
            public int size() {
3025
                return getChildren().size()+mainRepository.size();
3026
            }
3027

    
3028
            @Override
3029
            public UnmodifiableBasicSet<String> keySet() {
3030
                UnmodifiableBasicMap<String, DataStore> children = getChildren();
3031
                if( children.isEmpty() ) {
3032
                    return mainRepository.keySet();
3033
                }
3034
                return new UnmodifiableBasicSetChained<>(
3035
                        children.keySet(), 
3036
                        mainRepository.keySet()
3037
                );
3038
            }
3039

    
3040
            @Override
3041
            public Iterator<DataStore> iterator() {
3042
                final Iterator<String> it = this.keySet().iterator();
3043
                return new Iterator<DataStore>() {
3044
                    @Override
3045
                    public boolean hasNext() {
3046
                        return it.hasNext();
3047
                    }
3048

    
3049
                    @Override
3050
                    public DataStore next() {
3051
                        String name = it.next();
3052
                        return get(name);
3053
                    }
3054
                };
3055
            }
3056
        };
3057
        return repository;
3058
    }
3059
    
3060
}