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

History | View | Annotate | Download (100 KB)

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

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

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

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

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

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

    
173
import org.slf4j.Logger;
174
import org.slf4j.LoggerFactory;
175

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

    
180
    private static final Logger LOG = LoggerFactory
181
        .getLogger(DefaultFeatureStore.class);
182

    
183
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
184

    
185
    private DataStoreParameters parameters = null;
186
    private FeatureSelection selection;
187
    private FeatureLocks locks;
188

    
189
    private DelegateWeakReferencingObservable delegateObservable =
190
        new DelegateWeakReferencingObservable(this);
191

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

    
201
    private FeatureType defaultFeatureType = null;
202
    private List featureTypes = new ArrayList();
203

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

    
209
    private DefaultDataManager dataManager = null;
210

    
211
    private FeatureStoreProvider provider = null;
212

    
213
    private DefaultFeatureIndexes indexes;
214

    
215
    private DefaultFeatureStoreTransforms transforms;
216

    
217
    DelegatedDynObject metadata;
218

    
219
    private Set metadataChildren;
220

    
221
    private Long featureCount = null;
222

    
223
    private long temporalOid = 0;
224

    
225
    private FeatureCacheProvider cache;
226

    
227
    StateInformation state;
228

    
229
    FeatureStoreTimeSupport timeSupport;
230

    
231

    
232
    private class StateInformation extends HashMap<Object, Object> {
233

    
234
        private static final long serialVersionUID = 4109026189635185666L;
235

    
236
        private boolean broken;
237
        private Throwable breakingsCause;
238

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

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

    
251
        public boolean isBroken() {
252
            return this.broken;
253
        }
254

    
255
        public void broken() {
256
            this.broken = true;
257
        }
258

    
259
        public Throwable getBreakingsCause() {
260
            return this.breakingsCause;
261
        }
262

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

    
271

    
272

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

    
282
    public DefaultFeatureStore() {
283
        this.state = new StateInformation();
284
    }
285

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

    
290
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
291

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

    
297
        this.dataManager = (DefaultDataManager) dataManager;
298

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

    
307
    }
308

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

    
318
    @Override
319
    public DataStoreParameters getParameters() {
320
        return parameters;
321
    }
322

    
323
    public int getMode() {
324
        return this.mode;
325
    }
326

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

    
332
    @Override
333
    public Iterator getChildren() {
334
        return this.provider.getChilds();
335
    }
336

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

    
342
    public FeatureManager getFeatureManager() {
343
        return this.featureManager;
344
    }
345

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

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

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

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

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

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

    
427
        this.featureManager = null;
428
        this.spatialManager = null;
429

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

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

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

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

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

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

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

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

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

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

    
582
        }
583

    
584
        if (evaluatedAttr.isEmpty()) {
585
            evaluatedAttr = null;
586
        }
587

    
588
        state.set("evaluatedAttributes", evaluatedAttr);
589
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
590

    
591
    }
592

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

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

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

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

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

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

    
704
                    }
705

    
706
            }
707
        } catch(Throwable th) {
708
            state.setBreakingsCause(th);
709
        }
710

    
711

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

    
716
            if (defaultFeatureType == null ||
717
                    defaultFeatureType.getId() == null ||
718
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
719

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

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

    
744
        public DataStoreProviderServices getStoreProviderServices() {
745
                return this;
746
        }
747

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

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

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

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

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

    
774
            definition.addDynFieldString("defaultFeatureTypeId")
775
                .setMandatory(true).setPersistent(true);
776
        }
777
    }
778

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

    
789
    //
790
    // ====================================================================
791
    // Gestion de la seleccion
792
    //
793

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

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

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

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

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

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

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

    
868
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
869
    }
870

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

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

    
885
    //
886
    // ====================================================================
887
    // Gestion de notificaciones
888
    //
889

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

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

    
905
    }
906

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

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

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

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

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

    
939
    //
940
    // ====================================================================
941
    // Gestion de bloqueos
942
    //
943

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

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

    
961
    //
962
    // ====================================================================
963
    // Interface Observable
964
    //
965

    
966
    @Override
967
    public void disableNotifications() {
968
        this.delegateObservable.disableNotifications();
969

    
970
    }
971

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

    
977
    @Override
978
    public void beginComplexNotification() {
979
        this.delegateObservable.beginComplexNotification();
980

    
981
    }
982

    
983
    @Override
984
    public void endComplexNotification() {
985
        this.delegateObservable.endComplexNotification();
986

    
987
    }
988

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

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

    
1003
    @Override
1004
    public void deleteObservers() {
1005
        this.delegateObservable.deleteObservers();
1006

    
1007
    }
1008

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

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

    
1028
        } else if (observable instanceof FeatureStoreProvider) {
1029
            if (observable == this.provider) {
1030

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

    
1039
    //
1040
    // ====================================================================
1041
    // Edicion
1042
    //
1043

    
1044
    private void newVersionOfUpdate() {
1045
        this.versionOfUpdate++;
1046
    }
1047

    
1048
    private long currentVersionOfUpdate() {
1049
        return this.versionOfUpdate;
1050
    }
1051

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

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

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

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

    
1080
        if (featureTypeManager != null) {
1081
            featureTypeManager.dispose();
1082
            featureTypeManager = null;
1083

    
1084
        }
1085

    
1086
        // TODO implementar un dispose para estos dos
1087
        featureManager = null;
1088
        spatialManager = null;
1089

    
1090
        featureCount = null;
1091

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

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

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

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

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

    
1151
    private void invalidateIndexes() {
1152
        setIndexesValidStatus(false);
1153
    }
1154

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

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

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

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

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

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

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

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

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

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

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

    
1276
    private static EditableFeature lastChangedFeature = null;
1277

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

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

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

    
1312
    synchronized public void doInsert(EditableFeature feature)
1313
        throws DataException {
1314
        checkIsOwnFeature(feature);
1315

    
1316
        waitForIndexes();
1317

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

    
1330

    
1331
        featureManager.add(newFeature);
1332
        spatialManager.insertFeature(newFeature);
1333

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1695
        case MODE_APPEND:
1696
                return true;
1697

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

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

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

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

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

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

    
1748
            }
1749
            explorer.add(provider, params, true);
1750

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

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

    
1786
    //
1787
    // ====================================================================
1788
    // Obtencion de datos
1789
    // getDataCollection, getFeatureCollection
1790
    //
1791

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1975
    @Override
1976
    public void accept(Visitor visitor) throws BaseException {
1977
        this.accept(visitor, null);
1978
    }
1979

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

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

    
2005
    @Override
2006
    public void getFeatureSet(Observer observer) throws DataException {
2007
        checkNotInAppendMode();
2008
        this.getFeatureSet(null, observer);
2009
    }
2010

    
2011
    @Override
2012
    public void getFeatureSet(FeatureQuery query, Observer observer)
2013
        throws DataException {
2014
        class LoadInBackGround implements Runnable {
2015

    
2016
            private final FeatureStore store;
2017
            private final FeatureQuery query;
2018
            private final Observer observer;
2019

    
2020
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2021
                Observer observer) {
2022
                this.store = store;
2023
                this.query = query;
2024
                this.observer = observer;
2025
            }
2026

    
2027
            void notify(FeatureStoreNotification theNotification) {
2028
                observer.update(store, theNotification);
2029
            }
2030

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

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

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

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

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

    
2088
        DefaultFeature feature =
2089
            new DefaultFeature(this,
2090
                this.provider.getFeatureProviderByReference(
2091
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2092

    
2093
        if (!this.transforms.isEmpty()) {
2094
            return this.transforms.applyTransform(feature, featureType);
2095
        }
2096
        return feature;
2097
    }
2098

    
2099
    //
2100
    // ====================================================================
2101
    // Gestion de features
2102
    //
2103

    
2104
    private FeatureType fixFeatureType(DefaultFeatureType type)
2105
        throws DataException {
2106
        FeatureType original = this.getDefaultFeatureType();
2107

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

    
2120
                    } else
2121
                        if (type.isSubtypeOf(tmpType)) {
2122
                            found = true;
2123
                            original = tmpType;
2124
                            break;
2125
                        }
2126

    
2127
                }
2128
                if (!found) {
2129
                    throw new IllegalFeatureTypeException(getName());
2130
                }
2131
            }
2132
        }
2133

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

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

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

    
2178
        }
2179

    
2180
        return type;
2181
    }
2182

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

    
2210
    @Override
2211
    public FeatureType getDefaultFeatureType() throws DataException {
2212
        try {
2213

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

    
2226
            return avoidEditable(defaultFeatureType);
2227

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

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

    
2272
    public FeatureType getProviderDefaultFeatureType() {
2273
        return defaultFeatureType;
2274
    }
2275

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

    
2310
    public List getProviderFeatureTypes() throws DataException {
2311
        return Collections.unmodifiableList(this.featureTypes);
2312
    }
2313

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

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

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

    
2339
            return feature;
2340
        } catch (Exception e) {
2341
            throw new CreateFeatureException(e, getName());
2342
        }
2343
    }
2344

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

    
2357
    }
2358

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

    
2375
    @Override
2376
    public EditableFeature createNewFeature(boolean defaultValues)
2377
        throws DataException {
2378
        return this.createNewFeature(this.getDefaultFeatureType(),
2379
            defaultValues);
2380
    }
2381

    
2382
    @Override
2383
    public EditableFeature createNewFeature() throws DataException {
2384
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2385
    }
2386

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

    
2401
    @Override
2402
    public EditableFeatureType createFeatureType() {
2403
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2404
        return ftype;
2405
    }
2406

    
2407
    @Override
2408
    public EditableFeatureType createFeatureType(String id) {
2409
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2410
        return ftype;
2411
    }
2412

    
2413
    //
2414
    // ====================================================================
2415
    // Index related methods
2416
    //
2417

    
2418
    @Override
2419
    public FeatureIndexes getIndexes() {
2420
        return this.indexes;
2421
    }
2422

    
2423
    @Override
2424
    public FeatureIndex createIndex(FeatureType featureType,
2425
        String attributeName, String indexName) throws DataException {
2426
        return createIndex(null, featureType, attributeName, indexName);
2427
    }
2428

    
2429
    @Override
2430
    public FeatureIndex createIndex(String indexTypeName,
2431
        FeatureType featureType, String attributeName, String indexName)
2432
        throws DataException {
2433

    
2434
        return createIndex(indexTypeName, featureType, attributeName,
2435
            indexName, false, null);
2436
    }
2437

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

    
2446
    @Override
2447
    public FeatureIndex createIndex(String indexTypeName,
2448
        FeatureType featureType, String attributeName, String indexName,
2449
        final Observer observer) throws DataException {
2450

    
2451
        return createIndex(indexTypeName, featureType, attributeName,
2452
            indexName, true, observer);
2453
    }
2454

    
2455
    private FeatureIndex createIndex(String indexTypeName,
2456
        FeatureType featureType, String attributeName, String indexName,
2457
        boolean background, final Observer observer) throws DataException {
2458

    
2459
        checkNotInAppendMode();
2460
        FeatureIndexProviderServices index;
2461
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2462
                featureType, indexName,
2463
                featureType.getAttributeDescriptor(attributeName));
2464

    
2465
        try {
2466
            index.fill(background, observer);
2467
        } catch (FeatureIndexException e) {
2468
            throw new InitializeException(index.getName(), e);
2469
        }
2470

    
2471
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2472
        return index;
2473
    }
2474

    
2475
    //
2476
    // ====================================================================
2477
    // Transforms related methods
2478
    //
2479

    
2480
    @Override
2481
    public FeatureStoreTransforms getTransforms() {
2482
        return this.transforms;
2483
    }
2484

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

    
2531
    //
2532
    // ====================================================================
2533
    // UndoRedo related methods
2534
    //
2535

    
2536
    @Override
2537
    public boolean canRedo() {
2538
        return commands.canRedo();
2539
    }
2540

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

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

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

    
2560
    //
2561
    // ====================================================================
2562
    // Metadata related methods
2563
    //
2564

    
2565
    @Override
2566
    public Object getMetadataID() {
2567
        return this.provider.getSourceId();
2568
    }
2569

    
2570
    @Override
2571
    public void delegate(DynObject dynObject) {
2572
        this.metadata.delegate(dynObject);
2573
    }
2574

    
2575
    @Override
2576
    public DynClass getDynClass() {
2577
        return this.metadata.getDynClass();
2578
    }
2579

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

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

    
2615
    @Override
2616
    public boolean hasDynMethod(String name) {
2617
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2618
    }
2619

    
2620
    @Override
2621
    public void implement(DynClass dynClass) {
2622
        this.metadata.implement(dynClass);
2623
    }
2624

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

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

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

    
2646
    }
2647

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

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

    
2668
    public FeatureTypeManager getFeatureTypeManager() {
2669
        return this.featureTypeManager;
2670
    }
2671

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

    
2693
    private Long getTemporalOID() {
2694
        return this.temporalOid++;
2695
    }
2696

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

    
2713
    @Override
2714
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2715
        return ((DefaultFeature) feature).getData();
2716
    }
2717

    
2718
    @Override
2719
    public DataStore getStore() {
2720
        return this;
2721
    }
2722

    
2723
    @Override
2724
    public FeatureStore getFeatureStore() {
2725
        return this;
2726
    }
2727

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

    
2738
        featureCount = null;
2739
    }
2740

    
2741
    @Override
2742
    public FeatureCache getCache() {
2743
        return cache;
2744
    }
2745

    
2746
    @Override
2747
    public void clear() {
2748
        if (metadata != null) {
2749
            metadata.clear();
2750
        }
2751
    }
2752

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

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

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

    
2789
    }
2790

    
2791
    @Override
2792
    public boolean isKnownEnvelope() {
2793
        return this.provider.isKnownEnvelope();
2794
    }
2795

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

    
2801
    @Override
2802
    public int getRetrievedFeaturesLimit() {
2803
        return this.provider.getRetrievedFeaturesLimit();
2804
    }
2805

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

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

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

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

    
2873
    @Override
2874
    @SuppressWarnings("CloneDoesntCallSuperClone")
2875
    public Object clone() throws CloneNotSupportedException {
2876

    
2877
        DataStoreParameters dsp = getParameters();
2878

    
2879
        DefaultFeatureStore cloned_store = null;
2880

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

    
2893
    }
2894

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

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

    
2913
    @Override
2914
    public ExpressionBuilder createExpressionBuilder() {
2915
        ExpressionBuilder builder = null;
2916
//        if( this.provider instanceof FeatureStoreProvider_v2 ) {
2917
//            builder = ((FeatureStoreProvider_v2)this.provider).createExpression();
2918
//        }
2919
//        if( builder==null ) {
2920
            builder = ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
2921
//        }
2922
        return builder;
2923
    }
2924

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

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

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

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

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

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

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

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

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