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

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
import org.gvsig.fmap.dal.BaseStoresRepository;
51

    
52
import org.gvsig.fmap.dal.DALLocator;
53
import org.gvsig.fmap.dal.DataManager;
54
import org.gvsig.fmap.dal.DataQuery;
55
import org.gvsig.fmap.dal.DataServerExplorer;
56
import org.gvsig.fmap.dal.DataSet;
57
import org.gvsig.fmap.dal.DataStore;
58
import org.gvsig.fmap.dal.DataStoreNotification;
59
import org.gvsig.fmap.dal.DataStoreParameters;
60
import org.gvsig.fmap.dal.DataStoreProviderFactory;
61
import org.gvsig.fmap.dal.StoresRepository;
62
import org.gvsig.fmap.dal.exception.CloneException;
63
import org.gvsig.fmap.dal.exception.CloseException;
64
import org.gvsig.fmap.dal.exception.CreateException;
65
import org.gvsig.fmap.dal.exception.DataException;
66
import org.gvsig.fmap.dal.exception.InitializeException;
67
import org.gvsig.fmap.dal.exception.OpenException;
68
import org.gvsig.fmap.dal.exception.ReadException;
69
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
70
import org.gvsig.fmap.dal.exception.WriteException;
71
import org.gvsig.fmap.dal.feature.EditableFeature;
72
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
73
import org.gvsig.fmap.dal.feature.EditableFeatureType;
74
import org.gvsig.fmap.dal.feature.Feature;
75
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
76
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
77
import org.gvsig.fmap.dal.feature.FeatureCache;
78
import org.gvsig.fmap.dal.feature.FeatureIndex;
79
import org.gvsig.fmap.dal.feature.FeatureIndexes;
80
import org.gvsig.fmap.dal.feature.FeatureLocks;
81
import org.gvsig.fmap.dal.feature.FeatureQuery;
82
import org.gvsig.fmap.dal.feature.FeatureReference;
83
import org.gvsig.fmap.dal.feature.FeatureReferenceSelection;
84
import org.gvsig.fmap.dal.feature.FeatureRules;
85
import org.gvsig.fmap.dal.feature.FeatureSelection;
86
import org.gvsig.fmap.dal.feature.FeatureSet;
87
import org.gvsig.fmap.dal.feature.FeatureStore;
88
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
89
import org.gvsig.fmap.dal.feature.FeatureStoreProviderFactory;
90
import org.gvsig.fmap.dal.feature.FeatureStoreTransforms;
91
import org.gvsig.fmap.dal.feature.FeatureType;
92
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
93
import org.gvsig.fmap.dal.feature.FeatureStoreTimeSupport;
94
import org.gvsig.fmap.dal.feature.FeatureStoreTransform;
95
import org.gvsig.fmap.dal.feature.exception.AlreadyEditingException;
96
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
97
import org.gvsig.fmap.dal.feature.exception.CreateFeatureException;
98
import org.gvsig.fmap.dal.feature.exception.DataExportException;
99
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
100
import org.gvsig.fmap.dal.feature.exception.FinishEditingException;
101
import org.gvsig.fmap.dal.feature.exception.GetFeatureTypeException;
102
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureException;
103
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureTypeException;
104
import org.gvsig.fmap.dal.feature.exception.NeedEditingModeException;
105
import org.gvsig.fmap.dal.feature.exception.NoNewFeatureInsertException;
106
import org.gvsig.fmap.dal.feature.exception.NullFeatureTypeException;
107
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
108
import org.gvsig.fmap.dal.feature.exception.PersistenceCantFindFeatureTypeException;
109
import org.gvsig.fmap.dal.feature.exception.PersistenceStoreAlreadyLoadedException;
110
import org.gvsig.fmap.dal.feature.exception.SelectionNotAllowedException;
111
import org.gvsig.fmap.dal.feature.exception.StoreCancelEditingException;
112
import org.gvsig.fmap.dal.feature.exception.StoreDeleteEditableFeatureException;
113
import org.gvsig.fmap.dal.feature.exception.StoreDeleteFeatureException;
114
import org.gvsig.fmap.dal.feature.exception.StoreEditException;
115
import org.gvsig.fmap.dal.feature.exception.StoreInsertFeatureException;
116
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureException;
117
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureTypeException;
118
import org.gvsig.fmap.dal.feature.exception.ValidateFeaturesException;
119
import org.gvsig.fmap.dal.feature.exception.WriteNotAllowedException;
120
import org.gvsig.fmap.dal.feature.impl.featureset.DefaultFeatureSet;
121
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
122
import org.gvsig.fmap.dal.feature.impl.undo.DefaultFeatureCommandsStack;
123
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
124
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
125
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
126
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
127
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
128
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
129
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
130
import org.gvsig.fmap.dal.feature.spi.cache.FeatureCacheProvider;
131
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProviderServices;
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.resourcesstorage.ResourcesStorage;
171
import org.gvsig.tools.util.UnmodifiableBasicMap;
172
import org.gvsig.tools.visitor.VisitCanceledException;
173
import org.gvsig.tools.visitor.Visitor;
174

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

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

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

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

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

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

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

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

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

    
211
    private DefaultDataManager dataManager = null;
212

    
213
    private FeatureStoreProvider provider = null;
214

    
215
    private DefaultFeatureIndexes indexes;
216

    
217
    private DefaultFeatureStoreTransforms transforms;
218

    
219
    DelegatedDynObject metadata;
220

    
221
    private Set metadataChildren;
222

    
223
    private Long featureCount = null;
224

    
225
    private long temporalOid = 0;
226

    
227
    private FeatureCacheProvider cache;
228

    
229
    StateInformation state;
230

    
231
    FeatureStoreTimeSupport timeSupport;
232

    
233

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

    
236
        private static final long serialVersionUID = 4109026189635185666L;
237

    
238
        private boolean broken;
239
        private Throwable breakingsCause;
240

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

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

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

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

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

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

    
273

    
274

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

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

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

    
292
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
293

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

    
299
        this.dataManager = (DefaultDataManager) dataManager;
300

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

    
309
    }
310

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
584
        }
585

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

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

    
593
    }
594

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

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

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

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

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

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

    
706
                    }
707

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

    
713

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
907
    }
908

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

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

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

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

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

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

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

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

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

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

    
972
    }
973

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

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

    
983
    }
984

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

    
989
    }
990

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

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

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

    
1009
    }
1010

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

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

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

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

    
1041
    //
1042
    // ====================================================================
1043
    // Edicion
1044
    //
1045

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

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

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

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

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

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

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

    
1086
        }
1087

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

    
1092
        featureCount = null;
1093

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1278
    private static EditableFeature lastChangedFeature = null;
1279

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

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

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

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

    
1318
        waitForIndexes();
1319

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

    
1332

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1697
        case MODE_APPEND:
1698
                return true;
1699

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2181
        }
2182

    
2183
        return type;
2184
    }
2185

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

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

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

    
2229
            return avoidEditable(defaultFeatureType);
2230

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

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

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

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

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

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

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

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

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

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

    
2360
    }
2361

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2649
    }
2650

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

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

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

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

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

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

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

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

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

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

    
2741
        featureCount = null;
2742
    }
2743

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

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

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

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

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

    
2792
    }
2793

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

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

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

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

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

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

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

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

    
2880
        DataStoreParameters dsp = getParameters();
2881

    
2882
        DefaultFeatureStore cloned_store = null;
2883

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

    
2896
    }
2897

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2993
    @Override
2994
    public StoresRepository getStoresRepository() {
2995
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
2996
        StoresRepository localRepository = this.provider.getStoresRepository();
2997
        StoresRepository repository = new BaseStoresRepository(this.getName()) {
2998
            
2999
            @Override
3000
            protected DataStoreParameters getMyParameters(String name) {
3001
                // Uff, esta implementacion no es nada buena
3002
                UnmodifiableBasicMap<String, DataStore> children = getChildren();
3003
                if( children==null ) {
3004
                    return null;
3005
                }
3006
                DataStore store = children.get(name);
3007
                if( store==null ) {
3008
                    return null;
3009
                }
3010
                return store.getParameters();
3011
            }
3012

    
3013
            @Override
3014
            protected boolean isEmptyMyRepository() {
3015
                UnmodifiableBasicMap<String, DataStore> children = getChildren();
3016
                return children==null || children.isEmpty();
3017
            }
3018

    
3019
            @Override
3020
            protected int getMySize() {
3021
                UnmodifiableBasicMap<String, DataStore> children = getChildren();
3022
                if( children==null ) {
3023
                    return 0;
3024
                }
3025
                return children.size();
3026
            }
3027

    
3028
            @Override
3029
            public void add(String name, DataStoreParameters parameters) {
3030
                mainRepository.add(name, parameters);
3031
            }
3032

    
3033
            @Override
3034
            public void remove(String name) {
3035
                mainRepository.remove(name);
3036
            }
3037

    
3038
        };
3039
        if( localRepository!=null ) {
3040
            repository.addRepository(localRepository);
3041
        }
3042
        repository.addRepository(mainRepository);
3043
        return repository;
3044
    }
3045

    
3046
    @Override
3047
    public Feature getSampleFeature() {
3048
            Feature sampleFeature;
3049
            try {
3050
                FeatureSelection theSelection = this.getFeatureSelection();
3051
                if( theSelection!=null && !theSelection.isEmpty() ) {
3052
                    sampleFeature = theSelection.first();
3053
                } else {
3054
                    sampleFeature = this.first();
3055
                }
3056
                if( sampleFeature==null ) {
3057
                    sampleFeature = this.createNewFeature();
3058
                }
3059
            } catch (DataException ex) {
3060
                return null;
3061
            }
3062
            return sampleFeature;
3063
    }
3064
        
3065
}