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

History | View | Annotate | Download (89.8 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
import org.gvsig.fmap.dal.feature.spi.SQLBuilderBase;
31

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

    
43
import org.apache.commons.io.FilenameUtils;
44
import org.apache.commons.lang3.StringUtils;
45
import org.cresques.cts.IProjection;
46

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

    
166
import org.slf4j.Logger;
167
import org.slf4j.LoggerFactory;
168

    
169
public class DefaultFeatureStore extends AbstractDisposable implements
170
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
171

    
172
    private static final Logger LOG = LoggerFactory
173
        .getLogger(DefaultFeatureStore.class);
174

    
175
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
176

    
177
    private DataStoreParameters parameters = null;
178
    private FeatureSelection selection;
179
    private FeatureLocks locks;
180

    
181
    private DelegateWeakReferencingObservable delegateObservable =
182
        new DelegateWeakReferencingObservable(this);
183

    
184
    private FeatureCommandsStack commands;
185
    private FeatureTypeManager featureTypeManager;
186
    private FeatureManager featureManager;
187
    private SpatialManager spatialManager;
188

    
189
    private FeatureType defaultFeatureType = null;
190
    private List featureTypes = new ArrayList();
191

    
192
    private int mode = MODE_QUERY;
193
    private long versionOfUpdate = 0;
194
    private boolean hasStrongChanges = true;
195
    private boolean hasInserts = true;
196

    
197
    private DefaultDataManager dataManager = null;
198

    
199
    private FeatureStoreProvider provider = null;
200

    
201
    private DefaultFeatureIndexes indexes;
202

    
203
    private DefaultFeatureStoreTransforms transforms;
204

    
205
    DelegatedDynObject metadata;
206

    
207
    private Set metadataChildren;
208

    
209
    private Long featureCount = null;
210

    
211
    private long temporalOid = 0;
212

    
213
    private FeatureCacheProvider cache;
214

    
215
    StateInformation state;
216

    
217
    FeatureStoreTimeSupport timeSupport;
218

    
219

    
220
    private class StateInformation extends HashMap<Object, Object> {
221

    
222
        private static final long serialVersionUID = 4109026189635185666L;
223

    
224
        private boolean broken;
225
        private Throwable breakingsCause;
226

    
227
        @SuppressWarnings("OverridableMethodCallInConstructor")
228
        public StateInformation() {
229
            this.clear();
230
        }
231

    
232
        @Override
233
        public void clear() {
234
            this.broken = false;
235
            this.breakingsCause = null;
236
            super.clear();
237
        }
238

    
239
        public boolean isBroken() {
240
            return this.broken;
241
        }
242

    
243
        public void broken() {
244
            this.broken = true;
245
        }
246

    
247
        public Throwable getBreakingsCause() {
248
            return this.breakingsCause;
249
        }
250

    
251
        public void setBreakingsCause(Throwable cause) {
252
            if( this.breakingsCause==null ) {
253
                this.breakingsCause = cause;
254
            }
255
            this.broken = true;
256
        }
257
    }
258

    
259

    
260

    
261
    /*
262
     * TODO:
263
     *
264
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
265
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
266
     * featureType al que se le han cambiado las reglas de validacion cuando
267
     * hasStrongChanges=false.
268
     */
269

    
270
    public DefaultFeatureStore() {
271
        this.state = new StateInformation();
272
    }
273

    
274
    @Override
275
    public void intialize(DataManager dataManager,
276
        DataStoreParameters parameters) throws InitializeException {
277

    
278
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
279

    
280
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
281
            FeatureStore.METADATA_DEFINITION_NAME,
282
            MetadataManager.METADATA_NAMESPACE
283
        );
284

    
285
        this.dataManager = (DefaultDataManager) dataManager;
286

    
287
        this.parameters = parameters;
288
        this.transforms = new DefaultFeatureStoreTransforms(this);
289
        try {
290
            indexes = new DefaultFeatureIndexes(this);
291
        } catch (DataException e) {
292
            throw new InitializeException(e);
293
        }
294

    
295
    }
296

    
297
    @Override
298
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
299
        this.provider = (FeatureStoreProvider) provider;
300
        this.delegate((DynObject) provider);
301
        this.metadataChildren = new HashSet();
302
        this.metadataChildren.add(provider);
303
    }
304

    
305
    @Override
306
    public DataStoreParameters getParameters() {
307
        return parameters;
308
    }
309

    
310
    public int getMode() {
311
        return this.mode;
312
    }
313

    
314
    @Override
315
    public DataManager getManager() {
316
        return this.dataManager;
317
    }
318

    
319
    @Override
320
    public Iterator getChildren() {
321
        return this.provider.getChilds();
322
    }
323

    
324
    @Override
325
    public FeatureStoreProvider getProvider() {
326
        return this.provider;
327
    }
328

    
329
    public FeatureManager getFeatureManager() {
330
        return this.featureManager;
331
    }
332

    
333
    @Override
334
    public void setFeatureTypes(List types, FeatureType defaultType) {
335
        this.featureTypes = types;
336
        this.defaultFeatureType = defaultType;
337
    }
338

    
339
    public void open() throws OpenException {
340
        if (this.mode != MODE_QUERY) {
341
            // TODO: Se puede hacer un open estando en edicion ?
342
            try {
343
                throw new IllegalStateException();
344
            } catch(Exception ex) {
345
                LOG.warn("Opening a store in editing/append mode ("+this.getFullName()+").",ex);
346
            }
347
        }
348
        this.notifyChange(DataStoreNotification.BEFORE_OPEN);
349
        this.provider.open();
350
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
351
    }
352

    
353
    @Override
354
    public void refresh() throws OpenException, InitializeException {
355
        if (this.mode != MODE_QUERY) {
356
            throw new IllegalStateException();
357
        }
358
        this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH);
359
        if( state.isBroken() ) {
360
            this.load(state);
361
        } else {
362
            this.featureCount = null;
363
            this.provider.refresh();
364
        }
365
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
366
    }
367

    
368
    public void close() throws CloseException {
369
        if (this.mode != MODE_QUERY) {
370
            // TODO: Se puede hacer un close estando en edicion ?
371
            try {
372
                throw new IllegalStateException();
373
            } catch(Exception ex) {
374
                LOG.warn("Clossing a store in editing/append mode ("+this.getFullName()+").",ex);
375
            }
376
        }
377
        this.notifyChange(DataStoreNotification.BEFORE_CLOSE);
378
        this.featureCount = null;
379
        this.provider.close();
380
        this.notifyChange(DataStoreNotification.AFTER_CLOSE);
381
    }
382

    
383
    @Override
384
    protected void doDispose() throws BaseException {
385
        if (this.mode != MODE_QUERY) {
386
            // TODO: Se puede hacer un dispose estando en edicion ?
387
            try {
388
                throw new IllegalStateException();
389
            } catch(Exception ex) {
390
                LOG.warn("Dispossing a store in editing/append mode ("+this.getFullName()+").",ex);
391
            }
392
        }
393
        this.notifyChange(DataStoreNotification.BEFORE_DISPOSE);
394
        this.disposeIndexes();
395
        if( this.provider!=null ) {
396
            this.provider.dispose();
397
        }
398
        if (this.selection != null) {
399
            this.selection.dispose();
400
            this.selection = null;
401
        }
402
        this.commands = null;
403
        this.featureCount = null;
404
        if (this.locks != null) {
405
            // this.locks.dispose();
406
            this.locks = null;
407
        }
408

    
409
        if (this.featureTypeManager != null) {
410
            this.featureTypeManager.dispose();
411
            this.featureTypeManager = null;
412
        }
413

    
414
        this.featureManager = null;
415
        this.spatialManager = null;
416

    
417
        this.parameters = null;
418
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
419
        if (delegateObservable != null) {
420
            this.delegateObservable.deleteObservers();
421
            this.delegateObservable = null;
422
        }
423
    }
424

    
425
    @Override
426
    public boolean allowWrite() {
427
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
428
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
429
            return false;
430
        }
431
        return this.provider.allowWrite();
432
    }
433

    
434
    @Override
435
    public boolean canWriteGeometry(int geometryType) throws DataException {
436
        return this.provider.canWriteGeometry(geometryType, 0);
437
    }
438

    
439
    @Override
440
    public DataServerExplorer getExplorer() throws ReadException,
441
        ValidateDataParametersException {
442
        if( this.state.isBroken() ) {
443
            try {
444
                return this.provider.getExplorer();
445
            } catch(Throwable th) {
446
                return null;
447
            }
448
        } else {
449
            return this.provider.getExplorer();
450
        }
451
    }
452

    
453
    /*
454
     * public Metadata getMetadata() throws MetadataNotFoundException {
455
     * // TODO:
456
     * // Si el provider devuelbe null habria que ver de construir aqui
457
     * // los metadatos basicos, como el Envelope y el SRS.
458
     *
459
     * // TODO: Estando en edicion el Envelope deberia de
460
     * // actualizarse usando el spatialManager
461
     * return this.provider.getMetadata();
462
     * }
463
     */
464

    
465
    @Override
466
    public Envelope getEnvelope() throws DataException {
467
        if (this.mode == MODE_FULLEDIT) {
468
                // Just in case another thread tries to write in the store
469
                synchronized (this) {
470
                        return this.spatialManager.getEnvelope();
471
                        }
472
        }
473
        if (hasDynValue(DataStore.METADATA_ENVELOPE)){
474
            return (Envelope)getDynValue(DataStore.METADATA_ENVELOPE);
475
        }
476
        return this.provider.getEnvelope();
477
    }
478

    
479
    /**
480
     * @throws org.gvsig.fmap.dal.exception.DataException
481
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
482
     */
483
    @Override
484
    public IProjection getSRSDefaultGeometry() throws DataException {
485
        return this.getDefaultFeatureType().getDefaultSRS();
486
    }
487

    
488
    @Override
489
    public FeatureSelection createDefaultFeatureSelection()
490
        throws DataException {
491
        return new DefaultFeatureSelection(this);
492
    }
493

    
494
    @Override
495
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
496
        throws DataException {
497
        if (type.hasOID()) {
498
            return new DefaultFeatureProvider(type,
499
                this.provider.createNewOID());
500
        }
501
        return new DefaultFeatureProvider(type);
502
    }
503

    
504
    @Override
505
    public void saveToState(PersistentState state) throws PersistenceException {
506
        /*if (this.mode != FeatureStore.MODE_QUERY) {
507
            throw new PersistenceException(new IllegalStateException(
508
                this.getName()));
509
        }*/
510
        state.set("dataStoreName", this.getName());
511
        state.set("parameters", this.parameters);
512
        state.set("selection", this.selection);
513
        state.set("transforms", this.transforms);
514
        // TODO locks persistence
515
        // state.set("locks", this.locks);
516
        // TODO indexes persistence
517
        // state.set("indexes", this.indexes);
518
        Map evaluatedAttr = new HashMap(1);
519
        Iterator iterType = featureTypes.iterator();
520
        Iterator iterAttr;
521
        FeatureType type;
522
        DefaultFeatureAttributeDescriptor attr;
523
        List attrs;
524
        while (iterType.hasNext()) {
525
            type = (FeatureType) iterType.next();
526
            attrs = new ArrayList();
527
            iterAttr = type.iterator();
528
            while (iterAttr.hasNext()) {
529
                attr = (DefaultFeatureAttributeDescriptor) iterAttr.next();
530
                if ((attr.getEvaluator() != null)
531
                    && (attr.getEvaluator() instanceof Persistent)) {
532
                    attrs.add(attr);
533
                }
534
            }
535
            if (!attrs.isEmpty()) {
536
                evaluatedAttr.put(type.getId(), attrs);
537
            }
538

    
539
        }
540

    
541
        if (evaluatedAttr.isEmpty()) {
542
            evaluatedAttr = null;
543
        }
544

    
545
        state.set("evaluatedAttributes", evaluatedAttr);
546
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
547

    
548
    }
549

    
550
    @Override
551
    public void loadFromState(final PersistentState persistentState)
552
        throws PersistenceException {
553
        if (this.provider != null) {
554
            throw new PersistenceStoreAlreadyLoadedException(this.getName());
555
        }
556
        if (this.getManager() == null) {
557
            this.dataManager = (DefaultDataManager) DALLocator.getDataManager();
558
        }
559
        state.clear();
560
        try {
561
            state.put("parameters", persistentState.get("parameters"));
562
        } catch(Throwable th) {
563
            state.setBreakingsCause(th);
564
        }
565
        try {
566
            state.put("selection", persistentState.get("selection"));
567
        } catch(Throwable th) {
568
            state.setBreakingsCause(th);
569
        }
570
        try {
571
            state.put("transforms",  persistentState.get("transforms"));
572
        } catch(Throwable th) {
573
            state.setBreakingsCause(th);
574
        }
575
        try {
576
            state.put("evaluatedAttributes",  persistentState.get("evaluatedAttributes"));
577
        } catch(Throwable th) {
578
            state.setBreakingsCause(th);
579
        }
580
        try {
581
            state.put("defaultFeatureTypeId", persistentState.getString("defaultFeatureTypeId"));
582
        } catch(Throwable th) {
583
            state.setBreakingsCause(th);
584
        }
585
        load(state);
586
    }
587

    
588
    private void load(StateInformation state) {
589
        this.featureTypes = new ArrayList();
590
        this.defaultFeatureType = null;
591
        this.featureCount = null;
592

    
593
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
594
        try {
595
            intialize(dataManager, params);
596
        } catch(Throwable th) {
597
            state.setBreakingsCause(th);
598
        }
599

    
600
        try {
601
            DataStoreProvider prov = dataManager.createProvider(
602
                getStoreProviderServices(),
603
                params
604
            );
605
            setProvider(prov);
606
        } catch(Throwable th) {
607
            state.setBreakingsCause(th);
608
        }
609

    
610
        try {
611
            selection = (FeatureSelection) state.get("selection");
612
        } catch(Throwable th) {
613
            state.setBreakingsCause(th);
614
        }
615

    
616
        try {
617
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
618
            this.transforms.setFeatureStore(this);
619
            for( FeatureStoreTransform transform : this.transforms ) {
620
                try {
621
                    transform.setUp();
622
                } catch(Throwable th) {
623
                    state.setBreakingsCause(th);
624
                }
625
            }
626
        } catch(Throwable th) {
627
            state.setBreakingsCause(th);
628
        }
629

    
630
        try {
631
            Map evaluatedAttributes = (Map) state.get("evaluatedAttributes");
632
            if ((evaluatedAttributes != null) && !evaluatedAttributes.isEmpty()) {
633
                    Iterator iterEntries = evaluatedAttributes.entrySet().iterator();
634
                    while (iterEntries.hasNext()) {
635
                            Entry entry = (Entry) iterEntries.next();
636
                            List attrs = (List) entry.getValue();
637
                            if (attrs.isEmpty()) {
638
                                    continue;
639
                            }
640
                            int fTypePos = -1;
641
                            DefaultFeatureType type = null;
642
                            for (int i = 0; i < featureTypes.size(); i++) {
643
                                    type = (DefaultFeatureType) featureTypes.get(i);
644
                                    if (type.getId().equals(entry.getKey())) {
645
                                            fTypePos = i;
646
                                            break;
647
                                    }
648
                            }
649
                            if (type == null) {
650
                                    throw new PersistenceCantFindFeatureTypeException(
651
                                            getName(), (String) entry.getKey());
652
                            }
653
                            DefaultEditableFeatureType eType = (DefaultEditableFeatureType) type.getEditable();
654
                            Iterator<FeatureAttributeDescriptor> iterAttr = attrs.iterator();
655
                            while (iterAttr.hasNext()) {
656
                                    FeatureAttributeDescriptor attr = iterAttr.next();
657
                                    eType.addLike(attr);
658
                            }
659
                            featureTypes.set(fTypePos, eType.getNotEditableCopy());
660

    
661
                    }
662

    
663
            }
664
        } catch(Throwable th) {
665
            state.setBreakingsCause(th);
666
        }
667

    
668

    
669
        try {
670
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
671
            FeatureType ftype;
672

    
673
            if (defaultFeatureType == null ||
674
                    defaultFeatureType.getId() == null ||
675
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
676

    
677
                    ftype = getFeatureType(defaultFeatureTypeId);
678
                    if (ftype == null) {
679
                            /*
680
                             * Un error en el m?todo de PostgreSQL getName(), hace que
681
                             * el nombre del featureType sea valor retornado por el getProviderName()
682
                             * De momento se pone este parche para apa?arlo y poder mantener compatibilidad
683
                             * con proyectos antiguos (2.1 y 2.2)
684
                             */
685
                            ftype = getFeatureType(getName());
686
                            if(ftype == null ) {
687
                                    throw new RuntimeException("Can't locate feature type");
688
                            }
689
                    }
690
                    defaultFeatureType = ftype;
691
            }
692
        } catch(Throwable th) {
693
            state.setBreakingsCause(th);
694
        }
695

    
696
        LOG.info("load() broken:{}, {}, {}.",
697
                new Object[] { state.isBroken(), this.getProviderName(), params }
698
        );
699
    }
700

    
701
        public DataStoreProviderServices getStoreProviderServices() {
702
                return this;
703
        }
704

    
705
    public static void registerPersistenceDefinition() {
706
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
707
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
708
            DynStruct definition =
709
                manager.addDefinition(DefaultFeatureStore.class,
710
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
711
                        + " Persistent definition", null, null);
712
            definition.addDynFieldString("dataStoreName").setMandatory(true)
713
                .setPersistent(true);
714

    
715
            definition.addDynFieldObject("parameters")
716
                .setClassOfValue(DynObject.class).setMandatory(true)
717
                .setPersistent(true);
718

    
719
            definition.addDynFieldObject("selection")
720
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
721
                .setPersistent(true);
722

    
723
            definition.addDynFieldObject("transforms")
724
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
725
                .setMandatory(true).setPersistent(true);
726

    
727
            definition.addDynFieldMap("evaluatedAttributes")
728
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
729
                .setMandatory(false).setPersistent(true);
730

    
731
            definition.addDynFieldString("defaultFeatureTypeId")
732
                .setMandatory(true).setPersistent(true);
733
        }
734
    }
735

    
736
    public static void registerMetadataDefinition() throws MetadataException {
737
        MetadataManager manager = MetadataLocator.getMetadataManager();
738
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
739
            DynStruct metadataDefinition =
740
                manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
741
            metadataDefinition.extend(manager
742
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
743
        }
744
    }
745

    
746
    //
747
    // ====================================================================
748
    // Gestion de la seleccion
749
    //
750

    
751
    @Override
752
    public void setSelection(DataSet selection) throws DataException {
753
        this.setSelection((FeatureSet) selection);
754
    }
755

    
756
    @Override
757
    public DataSet createSelection() throws DataException {
758
        return createFeatureSelection();
759
    }
760

    
761
    @Override
762
    public DataSet getSelection() throws DataException {
763
        return this.getFeatureSelection();
764
    }
765

    
766
    @Override
767
    public void setSelection(FeatureSet selection) throws DataException {
768
        setSelection(selection, true);
769
    }
770

    
771
    public void setSelection(FeatureSet selection, boolean undoable)
772
        throws DataException {
773
        if (selection == null) {
774
            if (undoable) {
775
                throw new SelectionNotAllowedException(getName());
776
            }
777

    
778
        } else {
779
            if (selection.equals(this.selection)) {
780
                return;
781
            }
782
            if (!selection.isFromStore(this)) {
783
                throw new SelectionNotAllowedException(getName());
784
            }
785
        }
786

    
787
        if (this.selection != null) {
788
            this.selection.deleteObserver(this);
789
        }
790
        if (selection == null) {
791
            if (this.selection != null) {
792
                this.selection.dispose();
793
            }
794
            this.selection = null;
795
            return;
796
        }
797
        if (selection instanceof FeatureSelection) {
798
            if (undoable && isEditing()) {
799
                commands.selectionSet(this, this.selection,
800
                    (FeatureSelection) selection);
801
            }
802
            if (this.selection != null) {
803
                this.selection.dispose();
804
            }
805
            this.selection = (FeatureSelection) selection;
806
        } else {
807
            if (undoable && isEditing()) {
808
                commands.startComplex("_selectionSet");
809
            }
810
            if (selection instanceof DefaultFeatureSelection) {
811
                DefaultFeatureSelection defSelection =
812
                    (DefaultFeatureSelection) selection;
813
                defSelection.deselectAll(undoable);
814
                defSelection.select(selection, undoable);
815
            } else {
816
                this.selection.deselectAll();
817
                this.selection.select(selection);
818
            }
819
            if (undoable && isEditing()) {
820
                commands.endComplex();
821
            }
822
        }
823
        this.selection.addObserver(this);
824

    
825
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
826
    }
827

    
828
    @Override
829
    public FeatureSelection createFeatureSelection() throws DataException {
830
        return this.provider.createFeatureSelection();
831
    }
832

    
833
    @Override
834
    public FeatureSelection getFeatureSelection() throws DataException {
835
        if (selection == null) {
836
            this.selection = createFeatureSelection();
837
            this.selection.addObserver(this);
838
        }
839
        return selection;
840
    }
841

    
842
    //
843
    // ====================================================================
844
    // Gestion de notificaciones
845
    //
846

    
847
    @Override
848
    public void notifyChange(FeatureStoreNotification storeNotification) {
849
        try {
850
            delegateObservable.notifyObservers(storeNotification);
851
        } catch (Throwable ex) {
852
            LOG.warn("Problems notifying changes in the store '"+this.getName()+" ("+storeNotification.getType()+").",ex);
853
        }
854
    }
855

    
856
    @Override
857
    public void notifyChange(String notification) {
858
        if (delegateObservable != null) {
859
            notifyChange(new DefaultFeatureStoreNotification(this, notification));
860
        }
861

    
862
    }
863

    
864
    @Override
865
    public void notifyChange(String notification, FeatureProvider data) {
866
        Feature f = null;
867
        try {
868
            f = createFeature(data);
869
        } catch (Throwable ex) {
870
            LOG.warn("Problems creating a feature to notifying changes in the store '"+this.getName()+" ("+notification+").",ex);
871
        }
872
        notifyChange(notification, f);
873
    }
874

    
875
    public void notifyChange(String notification, Feature feature) {
876
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
877
            feature));
878
    }
879

    
880
    public void notifyChange(String notification, Command command) {
881
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
882
            command));
883
    }
884

    
885
    public void notifyChange(String notification, EditableFeatureType type) {
886
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
887
            type));
888
    }
889

    
890
    @Override
891
    public void notifyChange(String notification, Resource resource) {
892
        notifyChange(new DefaultFeatureStoreNotification(this,
893
            DataStoreNotification.RESOURCE_CHANGED));
894
    }
895

    
896
    //
897
    // ====================================================================
898
    // Gestion de bloqueos
899
    //
900

    
901
    @Override
902
    public boolean isLocksSupported() {
903
        return this.provider.isLocksSupported();
904
    }
905

    
906
    @Override
907
    public FeatureLocks getLocks() throws DataException {
908
        if (!this.provider.isLocksSupported()) {
909
            LOG.warn("Locks not supported");
910
            return null;
911
        }
912
        if (locks == null) {
913
            this.locks = this.provider.createFeatureLocks();
914
        }
915
        return locks;
916
    }
917

    
918
    //
919
    // ====================================================================
920
    // Interface Observable
921
    //
922

    
923
    @Override
924
    public void disableNotifications() {
925
        this.delegateObservable.disableNotifications();
926

    
927
    }
928

    
929
    @Override
930
    public void enableNotifications() {
931
        this.delegateObservable.enableNotifications();
932
    }
933

    
934
    @Override
935
    public void beginComplexNotification() {
936
        this.delegateObservable.beginComplexNotification();
937

    
938
    }
939

    
940
    @Override
941
    public void endComplexNotification() {
942
        this.delegateObservable.endComplexNotification();
943

    
944
    }
945

    
946
    @Override
947
    public void addObserver(Observer observer) {
948
        if (delegateObservable != null) {
949
            this.delegateObservable.addObserver(observer);
950
        }
951
    }
952

    
953
    @Override
954
    public void deleteObserver(Observer observer) {
955
        if (delegateObservable != null) {
956
            this.delegateObservable.deleteObserver(observer);
957
        }
958
    }
959

    
960
    @Override
961
    public void deleteObservers() {
962
        this.delegateObservable.deleteObservers();
963

    
964
    }
965

    
966
    //
967
    // ====================================================================
968
    // Interface Observer
969
    //
970
    // Usado para observar:
971
    // - su seleccion
972
    // - sus bloqueos
973
    // - sus recursos
974
    //
975

    
976
    @Override
977
    public void update(Observable observable, Object notification) {
978
        if (observable instanceof FeatureSet) {
979
            if (observable == this.selection) {
980
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
981
            } else if (observable == this.locks) {
982
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
983
            }
984

    
985
        } else if (observable instanceof FeatureStoreProvider) {
986
            if (observable == this.provider) {
987

    
988
            }
989
        } else if (observable instanceof FeatureReferenceSelection) {
990
            if(notification instanceof String){
991
                    this.notifyChange((String)notification);
992
            }
993
        }
994
    }
995

    
996
    //
997
    // ====================================================================
998
    // Edicion
999
    //
1000

    
1001
    private void newVersionOfUpdate() {
1002
        this.versionOfUpdate++;
1003
    }
1004

    
1005
    private long currentVersionOfUpdate() {
1006
        return this.versionOfUpdate;
1007
    }
1008

    
1009
    private void checkInEditingMode() throws NeedEditingModeException {
1010
        if (mode != MODE_FULLEDIT) {
1011
            throw new NeedEditingModeException(this.getName());
1012
        }
1013
    }
1014

    
1015
    private void checkNotInAppendMode() throws IllegalStateException {
1016
        if (mode == MODE_APPEND) {
1017
                        throw new IllegalStateException("Error: store "
1018
                                        + this.getFullName() + " is in append mode");
1019
        }
1020
    }
1021

    
1022
    private void checkIsOwnFeature(Feature feature)
1023
        throws IllegalFeatureException {
1024
        if (((DefaultFeature) feature).getStore() != this) {
1025
            throw new IllegalFeatureException(this.getName());
1026
        }
1027
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1028
        // fixFeatureType((DefaultFeatureType) feature.getType());
1029
    }
1030

    
1031
    private void exitEditingMode() {
1032
        if (commands != null) {
1033
            commands.clear();
1034
            commands = null;
1035
        }
1036

    
1037
        if (featureTypeManager != null) {
1038
            featureTypeManager.dispose();
1039
            featureTypeManager = null;
1040

    
1041
        }
1042

    
1043
        // TODO implementar un dispose para estos dos
1044
        featureManager = null;
1045
        spatialManager = null;
1046

    
1047
        featureCount = null;
1048

    
1049
        mode = MODE_QUERY;
1050
        hasStrongChanges = true; // Lo deja a true por si las moscas
1051
        hasInserts = true;
1052
    }
1053

    
1054
    @Override
1055
    synchronized public void edit() throws DataException {
1056
        edit(MODE_FULLEDIT);
1057
    }
1058

    
1059
    @Override
1060
    synchronized public void edit(int mode) throws DataException {
1061
        LOG.debug("Starting editing in mode: {}", mode);
1062
        try {
1063
            if (this.mode != MODE_QUERY) {
1064
                throw new AlreadyEditingException(this.getName());
1065
            }
1066
            if (!this.provider.supportsAppendMode()) {
1067
                mode = MODE_FULLEDIT;
1068
            }
1069
            switch (mode) {
1070
            case MODE_QUERY:
1071
                throw new IllegalStateException(this.getName());
1072

    
1073
            case MODE_FULLEDIT:
1074
                if (!this.transforms.isEmpty()) {
1075
                    throw new IllegalStateException(this.getName());
1076
                }
1077
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
1078
                invalidateIndexes();
1079
                featureManager = new FeatureManager();
1080
                featureTypeManager = new FeatureTypeManager(this);
1081
                spatialManager = new SpatialManager(this, provider.getEnvelope());
1082

    
1083
                commands = new DefaultFeatureCommandsStack(
1084
                        this, featureManager,
1085
                        spatialManager, featureTypeManager);
1086
                this.mode = MODE_FULLEDIT;
1087
                hasStrongChanges = false;
1088
                hasInserts = false;
1089
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1090
                break;
1091
            case MODE_APPEND:
1092
                if (!this.transforms.isEmpty()) {
1093
                    throw new IllegalStateException(this.getName());
1094
                }
1095
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
1096
                invalidateIndexes();
1097
                this.provider.beginAppend();
1098
                this.mode = MODE_APPEND;
1099
                hasInserts = false;
1100
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1101
                break;
1102
            }
1103
        } catch (Exception e) {
1104
            throw new StoreEditException(e, this.getName());
1105
        }
1106
    }
1107

    
1108
    private void invalidateIndexes() {
1109
        setIndexesValidStatus(false);
1110
    }
1111

    
1112
    private void setIndexesValidStatus(boolean valid) {
1113
        FeatureIndexes theIndexes = getIndexes();
1114
        LOG.debug("Setting the store indexes to valid status {}: {}", (valid
1115
            ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1116
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1117
            FeatureIndex index = (FeatureIndex) iterator.next();
1118
            if (index instanceof FeatureIndexProviderServices) {
1119
                FeatureIndexProviderServices indexServices =
1120
                    (FeatureIndexProviderServices) index;
1121
                indexServices.setValid(valid);
1122
            }
1123
        }
1124
    }
1125

    
1126
    private void updateIndexes() throws FeatureIndexException {
1127
        FeatureIndexes theIndexes = getIndexes();
1128
        LOG.debug("Refilling indexes: {}", theIndexes);
1129
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1130
            FeatureIndex index = (FeatureIndex) iterator.next();
1131
            if (index instanceof FeatureIndexProviderServices) {
1132
                FeatureIndexProviderServices indexServices =
1133
                    (FeatureIndexProviderServices) index;
1134
                indexServices.fill(true, null);
1135
            }
1136
        }
1137
    }
1138

    
1139
    private void waitForIndexes() {
1140
        FeatureIndexes theIndexes = getIndexes();
1141
        LOG.debug("Waiting for indexes to finish filling: {}", theIndexes);
1142
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1143
            FeatureIndex index = (FeatureIndex) iterator.next();
1144
            if (index instanceof FeatureIndexProviderServices) {
1145
                FeatureIndexProviderServices indexServices =
1146
                    (FeatureIndexProviderServices) index;
1147
                indexServices.waitForIndex();
1148
            }
1149
        }
1150
    }
1151

    
1152
    private void disposeIndexes() {
1153
        FeatureIndexes theIndexes = getIndexes();
1154
        LOG.debug("Disposing indexes: {}", theIndexes);
1155
        if( theIndexes==null ) {
1156
            return;
1157
        }
1158
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1159
            FeatureIndex index = (FeatureIndex) iterator.next();
1160
            if (index instanceof FeatureIndexProviderServices) {
1161
                FeatureIndexProviderServices indexServices =
1162
                    (FeatureIndexProviderServices) index;
1163
                indexServices.dispose();
1164
            }
1165
        }
1166
    }
1167

    
1168
    @Override
1169
    public boolean isEditing() {
1170
        return mode == MODE_FULLEDIT;
1171
    }
1172

    
1173
    @Override
1174
    public boolean isAppending() {
1175
        return mode == MODE_APPEND;
1176
    }
1177

    
1178
    @Override
1179
    synchronized public void update(EditableFeatureType type)
1180
        throws DataException {
1181
        try {
1182
            checkInEditingMode();
1183
            if (type == null) {
1184
                throw new NullFeatureTypeException(getName());
1185
            }
1186
            // FIXME: Comprobar que es un featureType aceptable.
1187
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
1188
            newVersionOfUpdate();
1189

    
1190
            FeatureType oldt = type.getSource().getCopy();
1191
            FeatureType newt = type.getCopy();
1192
            commands.update(newt, oldt);
1193

    
1194
            if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
1195
                hasStrongChanges = true;
1196
            }
1197
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1198
        } catch (Exception e) {
1199
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1200
        }
1201
    }
1202

    
1203
    @Override
1204
    public void delete(Feature feature) throws DataException {
1205
        this.commands.delete(feature);
1206
    }
1207

    
1208
    synchronized public void doDelete(Feature feature) throws DataException {
1209
        try {
1210
            checkInEditingMode();
1211
            checkIsOwnFeature(feature);
1212
            if (feature instanceof EditableFeature) {
1213
                throw new StoreDeleteEditableFeatureException(getName());
1214
            }
1215
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1216

    
1217
            //Update the featureManager and the spatialManager
1218
            featureManager.delete(feature.getReference());
1219
            spatialManager.deleteFeature(feature);
1220

    
1221
            newVersionOfUpdate();
1222
            hasStrongChanges = true;
1223
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1224
        } catch (Exception e) {
1225
            throw new StoreDeleteFeatureException(e, this.getName());
1226
        }
1227
    }
1228

    
1229
    private static EditableFeature lastChangedFeature = null;
1230

    
1231
    @Override
1232
    public synchronized void insert(EditableFeature feature)
1233
        throws DataException {
1234
        LOG.debug("In editing mode {}, insert feature: {}", mode, feature);
1235
        try {
1236
            switch (mode) {
1237
            case MODE_QUERY:
1238
                throw new NeedEditingModeException(this.getName());
1239

    
1240
            case MODE_APPEND:
1241
                checkIsOwnFeature(feature);
1242
                if (feature.getSource() != null) {
1243
                    throw new NoNewFeatureInsertException(this.getName());
1244
                }
1245
                this.featureCount = null;
1246
                notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1247
                feature.validate(Feature.UPDATE);
1248
                provider.append(((DefaultEditableFeature) feature).getData());
1249
                hasStrongChanges = true;
1250
                hasInserts = true;
1251
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1252
                break;
1253

    
1254
            case MODE_FULLEDIT:
1255
                if (feature.getSource() != null) {
1256
                    throw new NoNewFeatureInsertException(this.getName());
1257
                }
1258
                commands.insert(feature);
1259
            }
1260
        } catch (Exception e) {
1261
            throw new StoreInsertFeatureException(e, this.getName());
1262
        }
1263
    }
1264

    
1265
    synchronized public void doInsert(EditableFeature feature)
1266
        throws DataException {
1267
        checkIsOwnFeature(feature);
1268

    
1269
        waitForIndexes();
1270

    
1271
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1272
        newVersionOfUpdate();
1273
        if ((lastChangedFeature == null)
1274
            || (lastChangedFeature.getSource() != feature.getSource())) {
1275
            lastChangedFeature = feature;
1276
            feature.validate(Feature.UPDATE);
1277
            lastChangedFeature = null;
1278
        }
1279
        //Update the featureManager and the spatialManager
1280
        ((DefaultEditableFeature) feature).setInserted(true);
1281
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1282

    
1283

    
1284
        featureManager.add(newFeature);
1285
        spatialManager.insertFeature(newFeature);
1286

    
1287
        hasStrongChanges = true;
1288
        hasInserts = true;
1289
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1290
    }
1291

    
1292
    @Override
1293
    public void update(EditableFeature feature)
1294
    throws DataException {
1295
        if ((feature).getSource() == null) {
1296
            insert(feature);
1297
            return;
1298
        }
1299
        commands.update(feature, feature.getSource());
1300
    }
1301

    
1302
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1303
        throws DataException {
1304
        try {
1305
            checkInEditingMode();
1306
            checkIsOwnFeature(feature);
1307
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature);
1308
            newVersionOfUpdate();
1309
            if ((lastChangedFeature == null)
1310
                || (lastChangedFeature.getSource() != feature.getSource())) {
1311
                lastChangedFeature = feature;
1312
                feature.validate(Feature.UPDATE);
1313
                lastChangedFeature = null;
1314
            }
1315

    
1316
            //Update the featureManager and the spatialManager
1317
            Feature newf = feature.getNotEditableCopy();
1318
            featureManager.update(newf, oldFeature);
1319
            spatialManager.updateFeature(newf, oldFeature);
1320

    
1321
            hasStrongChanges = true;
1322
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1323
        } catch (Exception e) {
1324
            throw new StoreUpdateFeatureException(e, this.getName());
1325
        }
1326
    }
1327

    
1328
    @Override
1329
    synchronized public void redo() throws RedoException {
1330
        Command redo = commands.getNextRedoCommand();
1331
        try {
1332
            checkInEditingMode();
1333
        } catch (NeedEditingModeException ex) {
1334
            throw new RedoException(redo, ex);
1335
        }
1336
        notifyChange(FeatureStoreNotification.BEFORE_REDO, redo);
1337
        newVersionOfUpdate();
1338
        commands.redo();
1339
        hasStrongChanges = true;
1340
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1341
    }
1342

    
1343
    @Override
1344
    synchronized public void undo() throws UndoException {
1345
        Command undo = commands.getNextUndoCommand();
1346
        try {
1347
            checkInEditingMode();
1348
        } catch (NeedEditingModeException ex) {
1349
            throw new UndoException(undo, ex);
1350
        }
1351
        notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo);
1352
        newVersionOfUpdate();
1353
        commands.undo();
1354
        hasStrongChanges = true;
1355
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1356
    }
1357

    
1358
    @Override
1359
    public List getRedoInfos() {
1360
        if (isEditing() && (commands != null)) {
1361
            return commands.getRedoInfos();
1362
        } else {
1363
            return null;
1364
        }
1365
    }
1366

    
1367
    @Override
1368
    public List getUndoInfos() {
1369
        if (isEditing() && (commands != null)) {
1370
            return commands.getUndoInfos();
1371
        } else {
1372
            return null;
1373
        }
1374
    }
1375

    
1376
    public synchronized FeatureCommandsStack getCommandsStack()
1377
        throws DataException {
1378
        checkInEditingMode();
1379
        return commands;
1380
    }
1381

    
1382
    @Override
1383
    synchronized public void cancelEditing() throws DataException {
1384
        if( spatialManager!=null ) {
1385
            spatialManager.cancelModifies();
1386
        }
1387
        try {
1388
            switch (mode) {
1389
            case MODE_QUERY:
1390
                throw new NeedEditingModeException(this.getName());
1391

    
1392
            case MODE_APPEND:
1393
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1394
                provider.abortAppend();
1395
                exitEditingMode();
1396
                ((FeatureSelection) this.getSelection()).deselectAll();
1397
                updateIndexes();
1398
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1399

    
1400
            case MODE_FULLEDIT:
1401
                boolean clearSelection = this.hasStrongChanges;
1402
                if (this.selection instanceof FeatureReferenceSelection) {
1403
                    clearSelection = this.hasInserts;
1404
                }
1405
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1406
                exitEditingMode();
1407
                if (clearSelection) {
1408
                    ((FeatureSelection) this.getSelection()).deselectAll();
1409
                }
1410
                updateIndexes();
1411
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1412
            }
1413
        } catch (Exception e) {
1414
            throw new StoreCancelEditingException(e, this.getName());
1415
        }
1416
    }
1417

    
1418
    @Override
1419
    synchronized public void finishEditing() throws DataException {
1420
        LOG.debug("finish editing of mode: {}", mode);
1421
        try {
1422

    
1423
            /*
1424
             * Selection needs to be cleared when editing stops
1425
             * to prevent conflicts with selection remaining from
1426
             * editing mode.
1427
             */
1428
//            ((FeatureSelection) this.getSelection()).deselectAll();
1429

    
1430
            switch (mode) {
1431
            case MODE_QUERY:
1432
                throw new NeedEditingModeException(this.getName());
1433

    
1434
            case MODE_APPEND:
1435
                if( selection!=null ) {
1436
                    selection = null;
1437
                }
1438
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1439
                provider.endAppend();
1440
                exitEditingMode();
1441
                updateIndexes();
1442
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1443
                break;
1444

    
1445
            case MODE_FULLEDIT:
1446
                if (hasStrongChanges && !this.allowWrite()) {
1447
                    throw new WriteNotAllowedException(getName());
1448
                }
1449
                if(featureManager.isSelectionCompromised() && selection!=null ) {
1450
                    selection = null;
1451
                }
1452
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1453
                if (hasStrongChanges) {
1454
                    validateFeatures(Feature.FINISH_EDITING);
1455

    
1456
                    /*
1457
                     * This will throw a PerformEditingExceptionif the provider
1458
                     * does not accept the changes (for example, an invalid field name)
1459
                     */
1460
                    provider.performChanges(featureManager.getDeleted(),
1461
                        featureManager.getInserted(),
1462
                        featureManager.getUpdated(),
1463
                        featureTypeManager.getFeatureTypesChanged());
1464
                }
1465
                exitEditingMode();
1466
                updateIndexes();
1467
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1468
                break;
1469
            }
1470
        } catch (PerformEditingException pee) {
1471
            throw new WriteException(provider.getSourceId().toString(), pee);
1472
        } catch (Exception e) {
1473
            throw new FinishEditingException(e);
1474
        }
1475
    }
1476

    
1477
    /**
1478
     * Save changes in the provider without leaving the edit mode.
1479
     * Do not call observers to communicate a change of ediding mode.
1480
     * The operation's history is eliminated to prevent inconsistencies
1481
     * in the data.
1482
     *
1483
     * @throws DataException
1484
     */
1485
    @Override
1486
    synchronized public void commitChanges() throws DataException {
1487
      LOG.debug("commitChanges of mode: {}", mode);
1488
      if( !canCommitChanges() ) {
1489
              throw new WriteNotAllowedException(getName());
1490
      }
1491
      try {
1492
        switch (mode) {
1493
        case MODE_QUERY:
1494
          throw new NeedEditingModeException(this.getName());
1495

    
1496
        case MODE_APPEND:
1497
          this.provider.endAppend();
1498
          exitEditingMode();
1499
          invalidateIndexes();
1500
          this.provider.beginAppend();
1501
          hasInserts = false;
1502
          break;
1503

    
1504
        case MODE_FULLEDIT:
1505
          if (hasStrongChanges && !this.allowWrite()) {
1506
            throw new WriteNotAllowedException(getName());
1507
          }
1508
          if (hasStrongChanges) {
1509
            validateFeatures(Feature.FINISH_EDITING);
1510
            provider.performChanges(featureManager.getDeleted(),
1511
              featureManager.getInserted(),
1512
              featureManager.getUpdated(),
1513
              featureTypeManager.getFeatureTypesChanged());
1514
          }
1515
          invalidateIndexes();
1516
          featureManager = new FeatureManager();
1517
          featureTypeManager = new FeatureTypeManager(this);
1518
          spatialManager = new SpatialManager(this, provider.getEnvelope());
1519

    
1520
          commands =
1521
            new DefaultFeatureCommandsStack(this, featureManager,
1522
              spatialManager, featureTypeManager);
1523
          featureCount = null;
1524
          hasStrongChanges = false;
1525
          hasInserts = false;
1526
          break;
1527
        }
1528
      } catch (Exception e) {
1529
        throw new FinishEditingException(e);
1530
      }
1531
    }
1532

    
1533
    @Override
1534
    synchronized public boolean canCommitChanges() throws DataException {
1535
        if ( !this.allowWrite()) {
1536
                return false;
1537
        }
1538
            switch (mode) {
1539
            default:
1540
        case MODE_QUERY:
1541
                return false;
1542

    
1543
        case MODE_APPEND:
1544
                return true;
1545

    
1546
        case MODE_FULLEDIT:
1547
            List types = this.getFeatureTypes();
1548
            for( int i=0; i<types.size(); i++ ) {
1549
                    Object type = types.get(i);
1550
                    if( type instanceof DefaultEditableFeatureType ) {
1551
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1552
                                    return false;
1553
                            }
1554
                    }
1555
            }
1556
            return true;
1557
            }
1558
    }
1559

    
1560
    @Override
1561
    public void beginEditingGroup(String description)
1562
        throws NeedEditingModeException {
1563
        checkInEditingMode();
1564
        commands.startComplex(description);
1565
    }
1566

    
1567
    @Override
1568
    public void endEditingGroup() throws NeedEditingModeException {
1569
        checkInEditingMode();
1570
        commands.endComplex();
1571
    }
1572

    
1573
    @Override
1574
    public boolean isAppendModeSupported() {
1575
        return this.provider.supportsAppendMode();
1576
    }
1577

    
1578
    @Override
1579
    public void export(DataServerExplorer explorer, String provider,
1580
        NewFeatureStoreParameters params) throws DataException {
1581

    
1582
        if (this.getFeatureTypes().size() != 1) {
1583
            throw new NotYetImplemented(
1584
                "export whith more than one type not yet implemented");
1585
        }
1586
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1587
        FeatureStore target = null;
1588
        FeatureSet features = null;
1589
        DisposableIterator iterator = null;
1590
        try {
1591
            FeatureType type = this.getDefaultFeatureType();
1592
            if ((params.getDefaultFeatureType() == null)
1593
                || (params.getDefaultFeatureType().size() == 0)) {
1594
                params.setDefaultFeatureType(type.getEditable());
1595

    
1596
            }
1597
            explorer.add(provider, params, true);
1598

    
1599
            DataManager manager = DALLocator.getDataManager();
1600
            target = (FeatureStore) manager.openStore(provider, params);
1601
            FeatureType targetType = target.getDefaultFeatureType();
1602

    
1603
            target.edit(MODE_APPEND);
1604
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
1605
            if (featureSelection.getSize() > 0) {
1606
                features = this.getFeatureSelection();
1607
            } else {
1608
                if ((pkattrs != null) && (pkattrs.length > 0)) {
1609
                    FeatureQuery query = createFeatureQuery();
1610
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
1611
                        query.getOrder().add(pkattr.getName(), true);
1612
                    }
1613
                    features = this.getFeatureSet(query);
1614
                } else {
1615
                    features = this.getFeatureSet();
1616
                }
1617
            }
1618
            iterator = features.fastIterator();
1619
            while (iterator.hasNext()) {
1620
                DefaultFeature feature = (DefaultFeature) iterator.next();
1621
                target.insert(target.createNewFeature(targetType, feature));
1622
            }
1623
            target.finishEditing();
1624
            target.dispose();
1625
        } catch (Exception e) {
1626
            throw new DataExportException(e, params.toString());
1627
        } finally {
1628
            dispose(iterator);
1629
            dispose(features);
1630
            dispose(target);
1631
        }
1632
    }
1633

    
1634
    //
1635
    // ====================================================================
1636
    // Obtencion de datos
1637
    // getDataCollection, getFeatureCollection
1638
    //
1639

    
1640
    @Override
1641
    public DataSet getDataSet() throws DataException {
1642
        checkNotInAppendMode();
1643
        FeatureQuery query =
1644
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1645
        return new DefaultFeatureSet(this, query);
1646
    }
1647

    
1648
    @Override
1649
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1650
        checkNotInAppendMode();
1651
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1652
    }
1653

    
1654
    @Override
1655
    public void getDataSet(Observer observer) throws DataException {
1656
        checkNotInAppendMode();
1657
        this.getFeatureSet(null, observer);
1658
    }
1659

    
1660
    @Override
1661
    public void getDataSet(DataQuery dataQuery, Observer observer)
1662
        throws DataException {
1663
        checkNotInAppendMode();
1664
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1665
    }
1666

    
1667
    @Override
1668
    public FeatureSet getFeatureSet() throws DataException {
1669
        return this.getFeatureSet((FeatureQuery)null);
1670
    }
1671

    
1672
    @Override
1673
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1674
        throws DataException {
1675
        checkNotInAppendMode();
1676
        if( featureQuery==null ) {
1677
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1678
        }
1679
        return new DefaultFeatureSet(this, featureQuery);
1680
    }
1681

    
1682
    @Override
1683
    public FeatureSet getFeatureSet(String filter) throws DataException {
1684
        return this.getFeatureSet(filter, null, true);
1685
    }
1686

    
1687
    @Override
1688
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
1689
        return this.getFeatureSet(filter, sortBy, true);
1690
    }
1691

    
1692
    @Override
1693
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
1694
        FeatureQuery query = this.createFeatureQuery();
1695
        if( !StringUtils.isEmpty(filter) ) {
1696
            query.setFilter(filter);
1697
        }
1698
        if( !StringUtils.isEmpty(sortBy) ) {
1699
            query.getOrder().add(sortBy, asc);
1700
        }
1701
        return this.getFeatureSet(query);
1702
    }
1703
    
1704
    @Override
1705
    public List<Feature> getFeatures(String filter)  {
1706
        return this.getFeatures(filter, null, true);
1707
    }
1708

    
1709
    @Override
1710
    public List<Feature> getFeatures(String filter, String sortBy)  {
1711
        return this.getFeatures(filter, sortBy, true);
1712
    }
1713

    
1714
    @Override
1715
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
1716
        FeatureQuery query = this.createFeatureQuery();
1717
        if( !StringUtils.isEmpty(filter) ) {
1718
            query.setFilter(filter);
1719
        }
1720
        if( !StringUtils.isEmpty(sortBy) ) {
1721
            query.getOrder().add(sortBy, asc);
1722
        }
1723
        return this.getFeatures(query, 100);
1724
    }
1725
    
1726
    @Override
1727
    public List<Feature> getFeatures(FeatureQuery query)  {
1728
        return this.getFeatures(query, 100);
1729
    }
1730
    
1731
    @Override
1732
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
1733
        try {
1734
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
1735
            return pager.asList();
1736
        } catch (BaseException ex) {
1737
            throw new RuntimeException("Can't create the list of features.", ex);
1738
        }
1739
    }
1740

    
1741
    @Override
1742
    public List<Feature> getFeatures() {
1743
        return this.getFeatures(null, 500);
1744
    }
1745

    
1746
    @Override
1747
    public Feature findFirst(String filter) throws DataException {
1748
        return this.findFirst(filter, null, true);
1749
    }
1750

    
1751
    @Override
1752
    public Feature findFirst(String filter, String sortBy) throws DataException {
1753
        return this.findFirst(filter, sortBy, true);
1754
    }
1755

    
1756
    @Override
1757
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
1758
        FeatureSet set = this.getFeatureSet(filter, sortBy, asc);
1759
        if( set==null || set.isEmpty() ) {
1760
            return null;
1761
        }
1762
        DisposableIterator it = set.iterator();
1763
        Feature f = (Feature) it.next();
1764
        it.dispose();
1765
        return f;
1766
    }
1767
    
1768
    @Override
1769
    public void accept(Visitor visitor) throws BaseException {
1770
        FeatureSet set = getFeatureSet();
1771
        try {
1772
            set.accept(visitor);
1773
        } finally {
1774
            set.dispose();
1775
        }
1776
    }
1777

    
1778
    @Override
1779
    public void accept(Visitor visitor, DataQuery dataQuery)
1780
        throws BaseException {
1781
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
1782
        try {
1783
            set.accept(visitor);
1784
        } finally {
1785
            set.dispose();
1786
        }
1787
    }
1788

    
1789
    public FeatureType getFeatureType(FeatureQuery featureQuery)
1790
        throws DataException {
1791
        DefaultFeatureType fType =
1792
            (DefaultFeatureType) this.getFeatureType(featureQuery
1793
                .getFeatureTypeId());
1794
        if( featureQuery.hasAttributeNames() || featureQuery.hasConstantsAttributeNames() ) {
1795
            return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames() );
1796
        }
1797
        return fType;
1798
    }
1799

    
1800
    @Override
1801
    public void getFeatureSet(Observer observer) throws DataException {
1802
        checkNotInAppendMode();
1803
        this.getFeatureSet(null, observer);
1804
    }
1805

    
1806
    @Override
1807
    public void getFeatureSet(FeatureQuery query, Observer observer)
1808
        throws DataException {
1809
        class LoadInBackGround implements Runnable {
1810

    
1811
            private final FeatureStore store;
1812
            private final FeatureQuery query;
1813
            private final Observer observer;
1814

    
1815
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
1816
                Observer observer) {
1817
                this.store = store;
1818
                this.query = query;
1819
                this.observer = observer;
1820
            }
1821

    
1822
            void notify(FeatureStoreNotification theNotification) {
1823
                observer.update(store, theNotification);
1824
            }
1825

    
1826
            @Override
1827
            public void run() {
1828
                FeatureSet set = null;
1829
                try {
1830
                    set = store.getFeatureSet(query);
1831
                    notify(new DefaultFeatureStoreNotification(store,
1832
                        FeatureStoreNotification.LOAD_FINISHED, set));
1833
                } catch (Exception e) {
1834
                    notify(new DefaultFeatureStoreNotification(store,
1835
                        FeatureStoreNotification.LOAD_FINISHED, e));
1836
                } finally {
1837
                    dispose(set);
1838
                }
1839
            }
1840
        }
1841

    
1842
        checkNotInAppendMode();
1843
        if (query == null) {
1844
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
1845
        }
1846
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
1847
        Thread thread = new Thread(task, "Load Feature Set in background");
1848
        thread.start();
1849
    }
1850

    
1851
    @Override
1852
    public Feature getFeatureByReference(FeatureReference reference)
1853
        throws DataException {
1854
        checkNotInAppendMode();
1855
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
1856
        FeatureType featureType;
1857
        if (ref.getFeatureTypeId() == null) {
1858
            featureType = this.getDefaultFeatureType();
1859
        } else {
1860
            featureType = this.getFeatureType(ref.getFeatureTypeId());
1861
        }
1862
        return this.getFeatureByReference(reference, featureType);
1863
    }
1864

    
1865
    @Override
1866
    public Feature getFeatureByReference(FeatureReference reference,
1867
        FeatureType featureType) throws DataException {
1868
        checkNotInAppendMode();
1869
        featureType = fixFeatureType((DefaultFeatureType) featureType);
1870
        if (this.mode == MODE_FULLEDIT) {
1871
            Feature f = featureManager.get(reference, this, featureType);
1872
            if (f != null) {
1873
                return f;
1874
            }
1875
        }
1876

    
1877
        FeatureType sourceFeatureType = featureType;
1878
        if (!this.transforms.isEmpty()) {
1879
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
1880
        }
1881
        // TODO comprobar que el id es de este store
1882

    
1883
        DefaultFeature feature =
1884
            new DefaultFeature(this,
1885
                this.provider.getFeatureProviderByReference(
1886
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
1887

    
1888
        if (!this.transforms.isEmpty()) {
1889
            return this.transforms.applyTransform(feature, featureType);
1890
        }
1891
        return feature;
1892
    }
1893

    
1894
    //
1895
    // ====================================================================
1896
    // Gestion de features
1897
    //
1898

    
1899
    private FeatureType fixFeatureType(DefaultFeatureType type)
1900
        throws DataException {
1901
        FeatureType original = this.getDefaultFeatureType();
1902

    
1903
        if ((type == null) || type.equals(original)) {
1904
            return original;
1905
        } else {
1906
            if (!type.isSubtypeOf(original)) {
1907
                Iterator iter = this.getFeatureTypes().iterator();
1908
                FeatureType tmpType;
1909
                boolean found = false;
1910
                while (iter.hasNext()) {
1911
                    tmpType = (FeatureType) iter.next();
1912
                    if (type.equals(tmpType)) {
1913
                        return type;
1914

    
1915
                    } else
1916
                        if (type.isSubtypeOf(tmpType)) {
1917
                            found = true;
1918
                            original = tmpType;
1919
                            break;
1920
                        }
1921

    
1922
                }
1923
                if (!found) {
1924
                    throw new IllegalFeatureTypeException(getName());
1925
                }
1926
            }
1927
        }
1928

    
1929
        // Checks that type has all fields of pk
1930
        // else add the missing attributes at the end.
1931
        if (!original.hasOID()) {
1932
            // Gets original pk attributes
1933
            DefaultEditableFeatureType edOriginal =
1934
                (DefaultEditableFeatureType) original.getEditable();
1935
            FeatureAttributeDescriptor orgAttr;
1936
            Iterator edOriginalIter = edOriginal.iterator();
1937
            while (edOriginalIter.hasNext()) {
1938
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1939
                if (!orgAttr.isPrimaryKey()) {
1940
                    edOriginalIter.remove();
1941
                }
1942
            }
1943

    
1944
            // Checks if all pk attributes are in type
1945
            Iterator typeIterator;
1946
            edOriginalIter = edOriginal.iterator();
1947
            FeatureAttributeDescriptor attr;
1948
            while (edOriginalIter.hasNext()) {
1949
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1950
                typeIterator = type.iterator();
1951
                while (typeIterator.hasNext()) {
1952
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
1953
                    if (attr.getName().equals(orgAttr.getName())) {
1954
                        edOriginalIter.remove();
1955
                        break;
1956
                    }
1957
                }
1958
            }
1959

    
1960
            // add missing pk attributes if any
1961
            if (edOriginal.size() > 0) {
1962
                boolean isEditable = type instanceof DefaultEditableFeatureType;
1963
                DefaultEditableFeatureType edType =
1964
                    (DefaultEditableFeatureType) original.getEditable();
1965
                edType.clear();
1966
                edType.addAll(type);
1967
                edType.addAll(edOriginal);
1968
                if (!isEditable) {
1969
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
1970
                }
1971
            }
1972

    
1973
        }
1974

    
1975
        return type;
1976
    }
1977

    
1978
    @Override
1979
    public void validateFeatures(int mode) throws DataException {
1980
        FeatureSet collection = null;
1981
        DisposableIterator iter = null;
1982
        try {
1983
            FeatureRules rules = this.getDefaultFeatureType().getRules();
1984
            if( rules==null || rules.isEmpty() ) {
1985
                return;
1986
            }
1987
            checkNotInAppendMode();
1988
            collection = this.getFeatureSet();
1989
            iter = collection.fastIterator();
1990
            long previousVersionOfUpdate = currentVersionOfUpdate();
1991
            while (iter.hasNext()) {
1992
                ((DefaultFeature) iter.next()).validate(mode);
1993
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
1994
                    throw new ConcurrentDataModificationException(getName());
1995
                }
1996
            }
1997
        } catch (Exception e) {
1998
            throw new ValidateFeaturesException(e, getName());
1999
        } finally {
2000
            DisposeUtils.disposeQuietly(iter);
2001
            DisposeUtils.disposeQuietly(collection);
2002
        }
2003
    }
2004

    
2005
    @Override
2006
    public FeatureType getDefaultFeatureType() throws DataException {
2007
        try {
2008

    
2009
            if (isEditing()) {
2010
                FeatureType auxFeatureType =
2011
                    featureTypeManager.getType(defaultFeatureType.getId());
2012
                if (auxFeatureType != null) {
2013
                    return avoidEditable(auxFeatureType);
2014
                }
2015
            }
2016
            FeatureType type = this.transforms.getDefaultFeatureType();
2017
            if (type != null) {
2018
                return avoidEditable(type);
2019
            }
2020

    
2021
            return avoidEditable(defaultFeatureType);
2022

    
2023
        } catch (Exception e) {
2024
            throw new GetFeatureTypeException(e, getName());
2025
        }
2026
    }
2027

    
2028
    private FeatureType avoidEditable(FeatureType ft) {
2029
        if (ft instanceof EditableFeatureType) {
2030
            return ((EditableFeatureType) ft).getNotEditableCopy();
2031
        } else {
2032
            return ft;
2033
        }
2034
    }
2035

    
2036
    @Override
2037
    public FeatureType getFeatureType(String featureTypeId)
2038
        throws DataException {
2039
        if (featureTypeId == null) {
2040
            return this.getDefaultFeatureType();
2041
        }
2042
        try {
2043
            if (isEditing()) {
2044
                FeatureType auxFeatureType =
2045
                    featureTypeManager.getType(featureTypeId);
2046
                if (auxFeatureType != null) {
2047
                    return auxFeatureType;
2048
                }
2049
            }
2050
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2051
            if (type != null) {
2052
                return type;
2053
            }
2054
            Iterator iter = this.featureTypes.iterator();
2055
            while (iter.hasNext()) {
2056
                type = (FeatureType) iter.next();
2057
                if (type.getId().equals(featureTypeId)) {
2058
                    return type;
2059
                }
2060
            }
2061
            return null;
2062
        } catch (Exception e) {
2063
            throw new GetFeatureTypeException(e, getName());
2064
        }
2065
    }
2066

    
2067
    public FeatureType getProviderDefaultFeatureType() {
2068
        return defaultFeatureType;
2069
    }
2070

    
2071
    @Override
2072
    public List getFeatureTypes() throws DataException {
2073
        try {
2074
            List types;
2075
            if (isEditing()) {
2076
                types = new ArrayList();
2077
                Iterator it = featureTypes.iterator();
2078
                while (it.hasNext()) {
2079
                    FeatureType type = (FeatureType) it.next();
2080
                    FeatureType typeaux =
2081
                        featureTypeManager.getType(type.getId());
2082
                    if (typeaux != null) {
2083
                        types.add(typeaux);
2084
                    } else {
2085
                        types.add(type);
2086
                    }
2087
                }
2088
                it = featureTypeManager.newsIterator();
2089
                while (it.hasNext()) {
2090
                    FeatureType type = (FeatureType) it.next();
2091
                    types.add(type);
2092
                }
2093
            } else {
2094
                types = this.transforms.getFeatureTypes();
2095
                if (types == null) {
2096
                    types = featureTypes;
2097
                }
2098
            }
2099
            return Collections.unmodifiableList(types);
2100
        } catch (Exception e) {
2101
            throw new GetFeatureTypeException(e, getName());
2102
        }
2103
    }
2104

    
2105
    public List getProviderFeatureTypes() throws DataException {
2106
        return Collections.unmodifiableList(this.featureTypes);
2107
    }
2108

    
2109
    @Override
2110
    public Feature createFeature(FeatureProvider data) throws DataException {
2111
        DefaultFeature feature = new DefaultFeature(this, data);
2112
        return feature;
2113
    }
2114

    
2115
    public Feature createFeature(FeatureProvider data, FeatureType type)
2116
        throws DataException {
2117
        // FIXME: falta por implementar
2118
        // Comprobar si es un subtipo del feature de data
2119
        // y construir un feature usando el subtipo.
2120
        // Probablemente requiera generar una copia del data.
2121
        throw new NotYetImplemented();
2122
    }
2123

    
2124
    @Override
2125
    public EditableFeature createNewFeature(FeatureType type,
2126
        Feature defaultValues) throws DataException {
2127
        try {
2128
            FeatureProvider data = createNewFeatureProvider(type);
2129
            DefaultEditableFeature feature =
2130
                new DefaultEditableFeature(this, data);
2131
            feature.initializeValues(defaultValues);
2132
            data.setNew(true);
2133

    
2134
            return feature;
2135
        } catch (Exception e) {
2136
            throw new CreateFeatureException(e, getName());
2137
        }
2138
    }
2139

    
2140
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2141
        throws DataException {
2142
        type = this.fixFeatureType((DefaultFeatureType) type);
2143
        FeatureProvider data = this.provider.createFeatureProvider(type);
2144
        data.setNew(true);
2145
        if (type.hasOID() && (data.getOID() == null)) {
2146
            data.setOID(this.provider.createNewOID());
2147
        } else {
2148
            data.setOID(this.getTemporalOID());
2149
        }
2150
        return data;
2151

    
2152
    }
2153

    
2154
    @Override
2155
    public EditableFeature createNewFeature(FeatureType type,
2156
        boolean defaultValues) throws DataException {
2157
        try {
2158
            FeatureProvider data = createNewFeatureProvider(type);
2159
            DefaultEditableFeature feature =
2160
                new DefaultEditableFeature(this, data);
2161
            if (defaultValues) {
2162
                feature.initializeValues();
2163
            }
2164
            return feature;
2165
        } catch (Exception e) {
2166
            throw new CreateFeatureException(e, getName());
2167
        }
2168
    }
2169

    
2170
    @Override
2171
    public EditableFeature createNewFeature(boolean defaultValues)
2172
        throws DataException {
2173
        return this.createNewFeature(this.getDefaultFeatureType(),
2174
            defaultValues);
2175
    }
2176

    
2177
    @Override
2178
    public EditableFeature createNewFeature() throws DataException {
2179
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2180
    }
2181

    
2182
    @Override
2183
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2184
        FeatureType ft = this.getDefaultFeatureType();
2185
        EditableFeature f = this.createNewFeature(ft, false);
2186
                for( FeatureAttributeDescriptor desc : ft ) {
2187
                        try {
2188
                                f.set(desc.getName(), defaultValues.get(desc.getName()));
2189
                        } catch(Throwable th) {
2190
                                // Ignore
2191
                        }
2192
                }
2193
        return f;
2194
    }
2195

    
2196
    @Override
2197
    public EditableFeatureType createFeatureType() {
2198
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2199
        return ftype;
2200
    }
2201

    
2202
    @Override
2203
    public EditableFeatureType createFeatureType(String id) {
2204
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2205
        return ftype;
2206
    }
2207

    
2208
    //
2209
    // ====================================================================
2210
    // Index related methods
2211
    //
2212

    
2213
    @Override
2214
    public FeatureIndexes getIndexes() {
2215
        return this.indexes;
2216
    }
2217

    
2218
    @Override
2219
    public FeatureIndex createIndex(FeatureType featureType,
2220
        String attributeName, String indexName) throws DataException {
2221
        return createIndex(null, featureType, attributeName, indexName);
2222
    }
2223

    
2224
    @Override
2225
    public FeatureIndex createIndex(String indexTypeName,
2226
        FeatureType featureType, String attributeName, String indexName)
2227
        throws DataException {
2228

    
2229
        return createIndex(indexTypeName, featureType, attributeName,
2230
            indexName, false, null);
2231
    }
2232

    
2233
    @Override
2234
    public FeatureIndex createIndex(FeatureType featureType,
2235
        String attributeName, String indexName, Observer observer)
2236
        throws DataException {
2237
        return createIndex(null, featureType, attributeName, indexName,
2238
            observer);
2239
    }
2240

    
2241
    @Override
2242
    public FeatureIndex createIndex(String indexTypeName,
2243
        FeatureType featureType, String attributeName, String indexName,
2244
        final Observer observer) throws DataException {
2245

    
2246
        return createIndex(indexTypeName, featureType, attributeName,
2247
            indexName, true, observer);
2248
    }
2249

    
2250
    private FeatureIndex createIndex(String indexTypeName,
2251
        FeatureType featureType, String attributeName, String indexName,
2252
        boolean background, final Observer observer) throws DataException {
2253

    
2254
        checkNotInAppendMode();
2255
        FeatureIndexProviderServices index;
2256
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2257
                featureType, indexName,
2258
                featureType.getAttributeDescriptor(attributeName));
2259

    
2260
        try {
2261
            index.fill(background, observer);
2262
        } catch (FeatureIndexException e) {
2263
            throw new InitializeException(index.getName(), e);
2264
        }
2265

    
2266
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2267
        return index;
2268
    }
2269

    
2270
    //
2271
    // ====================================================================
2272
    // Transforms related methods
2273
    //
2274

    
2275
    @Override
2276
    public FeatureStoreTransforms getTransforms() {
2277
        return this.transforms;
2278
    }
2279

    
2280
    @Override
2281
    public FeatureQuery createFeatureQuery() {
2282
        return new DefaultFeatureQuery();
2283
    }
2284

    
2285
    @Override
2286
    public DataQuery createQuery() {
2287
        return createFeatureQuery();
2288
    }
2289

    
2290
    //
2291
    // ====================================================================
2292
    // UndoRedo related methods
2293
    //
2294

    
2295
    @Override
2296
    public boolean canRedo() {
2297
        return commands.canRedo();
2298
    }
2299

    
2300
    @Override
2301
    public boolean canUndo() {
2302
        return commands.canUndo();
2303
    }
2304

    
2305
    @Override
2306
    public void redo(int num) throws RedoException {
2307
        for (int i = 0; i < num; i++) {
2308
            redo();
2309
        }
2310
    }
2311

    
2312
    @Override
2313
    public void undo(int num) throws UndoException {
2314
        for (int i = 0; i < num; i++) {
2315
            undo();
2316
        }
2317
    }
2318

    
2319
    //
2320
    // ====================================================================
2321
    // Metadata related methods
2322
    //
2323

    
2324
    @Override
2325
    public Object getMetadataID() {
2326
        return this.provider.getSourceId();
2327
    }
2328

    
2329
    @Override
2330
    public void delegate(DynObject dynObject) {
2331
        this.metadata.delegate(dynObject);
2332
    }
2333

    
2334
    @Override
2335
    public DynClass getDynClass() {
2336
        return this.metadata.getDynClass();
2337
    }
2338

    
2339
    @Override
2340
        public Object getDynValue(String name) throws DynFieldNotFoundException {
2341
                if( this.transforms.hasDynValue(name) ) {
2342
                        return this.transforms.getDynValue(name);
2343
                }
2344
                if (this.metadata.hasDynValue(name)) {
2345
                        return this.metadata.getDynValue(name);
2346
                }
2347
                if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2348
                        return this.provider.getProviderName();
2349
                } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2350
                        return this.provider.getSourceId();
2351
                } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2352
                        try {
2353
                                return this.getDefaultFeatureType();
2354
                        } catch (DataException e) {
2355
                                return null;
2356
                        }
2357
                }
2358
                return this.metadata.getDynValue(name);
2359
        }
2360

    
2361
    @Override
2362
    public boolean hasDynValue(String name) {
2363
                if( this.transforms.hasDynValue(name) ) {
2364
                        return true;
2365
                }
2366
        return this.metadata.hasDynValue(name);
2367
    }
2368

    
2369
    @Override
2370
    public boolean hasDynMethod(String name) {
2371
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2372
    }
2373

    
2374
    @Override
2375
    public void implement(DynClass dynClass) {
2376
        this.metadata.implement(dynClass);
2377
    }
2378

    
2379
    @Override
2380
    public Object invokeDynMethod(String name, Object[] args)
2381
        throws DynMethodException {
2382
        return this.metadata.invokeDynMethod(this, name, args);
2383
    }
2384

    
2385
    @Override
2386
    public Object invokeDynMethod(int code, Object[] args)
2387
        throws DynMethodException {
2388
        return this.metadata.invokeDynMethod(this, code, args);
2389
    }
2390

    
2391
    @Override
2392
    public void setDynValue(String name, Object value)
2393
        throws DynFieldNotFoundException {
2394
                if( this.transforms.hasDynValue(name) ) {
2395
                        this.transforms.setDynValue(name, value);
2396
                        return;
2397
                }
2398
        this.metadata.setDynValue(name, value);
2399

    
2400
    }
2401

    
2402
    /*
2403
     * (non-Javadoc)
2404
     *
2405
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2406
     */
2407
    @Override
2408
    public Set getMetadataChildren() {
2409
        return this.metadataChildren;
2410
    }
2411

    
2412
    /*
2413
     * (non-Javadoc)
2414
     *
2415
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2416
     */
2417
    @Override
2418
    public String getMetadataName() {
2419
        return this.provider.getProviderName();
2420
    }
2421

    
2422
    public FeatureTypeManager getFeatureTypeManager() {
2423
        return this.featureTypeManager;
2424
    }
2425

    
2426
    @Override
2427
    public long getFeatureCount() throws DataException {
2428
        if (featureCount == null) {
2429
            featureCount = this.provider.getFeatureCount();
2430
        }
2431
        if (this.isEditing()) {
2432
            if(this.isAppending()) {
2433
                try{
2434
                    throw new IllegalStateException();
2435
                } catch(IllegalStateException e) {
2436
                    LOG.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
2437
                }
2438
                return -1;
2439
            } else {
2440
                return featureCount
2441
                    + this.featureManager.getDeltaSize();
2442
            }
2443
        }
2444
        return featureCount;
2445
    }
2446

    
2447
    private Long getTemporalOID() {
2448
        return this.temporalOid++;
2449
    }
2450

    
2451
    @Override
2452
    public FeatureType getProviderFeatureType(String featureTypeId) {
2453
        if (featureTypeId == null) {
2454
            return this.defaultFeatureType;
2455
        }
2456
        FeatureType type;
2457
        Iterator iter = this.featureTypes.iterator();
2458
        while (iter.hasNext()) {
2459
            type = (FeatureType) iter.next();
2460
            if (type.getId().equals(featureTypeId)) {
2461
                return type;
2462
            }
2463
        }
2464
        return null;
2465
    }
2466

    
2467
    @Override
2468
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2469
        return ((DefaultFeature) feature).getData();
2470
    }
2471

    
2472
    @Override
2473
    public DataStore getStore() {
2474
        return this;
2475
    }
2476

    
2477
    @Override
2478
    public FeatureStore getFeatureStore() {
2479
        return this;
2480
    }
2481

    
2482
    @Override
2483
    public void createCache(String name, DynObject parameters)
2484
        throws DataException {
2485
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2486
        if (cache == null) {
2487
            throw new CreateException("FeaureCacheProvider", null);
2488
        }
2489
        cache.apply(this, provider);
2490
        provider = cache;
2491

    
2492
        featureCount = null;
2493
    }
2494

    
2495
    @Override
2496
    public FeatureCache getCache() {
2497
        return cache;
2498
    }
2499

    
2500
    @Override
2501
    public void clear() {
2502
        if (metadata != null) {
2503
            metadata.clear();
2504
        }
2505
    }
2506

    
2507
    @Override
2508
    public String getName() {
2509
        if( this.provider != null ) {
2510
            return this.provider.getName();
2511
        }
2512
        if( this.parameters instanceof HasAFile ) {
2513
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
2514
        }
2515
        return "unknow";
2516
    }
2517

    
2518
    @Override
2519
    public String getFullName() {
2520
        try {
2521
            if( this.provider!=null ) {
2522
                return this.provider.getFullName();
2523
            }
2524
            if( this.parameters instanceof HasAFile ) {
2525
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
2526
            }
2527
            return null;
2528
        } catch(Throwable th) {
2529
            return null;
2530
        }
2531
    }
2532

    
2533
    @Override
2534
    public String getProviderName() {
2535
        if( this.provider!=null ) {
2536
            return this.provider.getProviderName();
2537
        }
2538
        if( this.parameters != null ) {
2539
            return this.parameters.getDataStoreName();
2540
        }
2541
        return null;
2542

    
2543
    }
2544

    
2545
    @Override
2546
    public boolean isKnownEnvelope() {
2547
        return this.provider.isKnownEnvelope();
2548
    }
2549

    
2550
    @Override
2551
    public boolean hasRetrievedFeaturesLimit() {
2552
        return this.provider.hasRetrievedFeaturesLimit();
2553
    }
2554

    
2555
    @Override
2556
    public int getRetrievedFeaturesLimit() {
2557
        return this.provider.getRetrievedFeaturesLimit();
2558
    }
2559

    
2560
    @Override
2561
    public Interval getInterval() {
2562
        if( this.timeSupport!=null ) {
2563
            return this.timeSupport.getInterval();
2564
        }
2565
        return this.provider.getInterval();
2566
    }
2567

    
2568
    @Override
2569
    public Collection getTimes() {
2570
        if( this.timeSupport!=null ) {
2571
            return this.timeSupport.getTimes();
2572
        }
2573
        return this.provider.getTimes();
2574
    }
2575

    
2576
    @Override
2577
    public Collection getTimes(Interval interval) {
2578
        if( this.timeSupport!=null ) {
2579
            return this.timeSupport.getTimes(interval);
2580
        }
2581
        return this.provider.getTimes(interval);
2582
    }
2583

    
2584
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
2585
        if( this.isEditing() ) {
2586
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
2587
        }
2588
        if( !this.transforms.isEmpty() ) {
2589
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
2590
        }
2591
        FeatureType ft = this.defaultFeatureType;
2592
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
2593
        if( attr == null ) {
2594
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
2595
        }
2596
        EditableFeatureType eft = ft.getEditable();
2597
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
2598
        if( attr != null ) {
2599
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
2600
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
2601
            }
2602
            eft.remove(attr.getName());
2603
        }
2604
        EditableFeatureAttributeDescriptor attrTime = eft.add(
2605
            timeSupport.getAttributeName(), 
2606
            timeSupport.getDataType()
2607
        );
2608
        attrTime.setIsTime(true);
2609
        attrTime.setFeatureAttributeEmulator(timeSupport);
2610
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
2611
        this.defaultFeatureType = eft.getNotEditableCopy();
2612
        
2613
        this.timeSupport = timeSupport;
2614
    }
2615

    
2616
    @Override
2617
    @SuppressWarnings("CloneDoesntCallSuperClone")
2618
    public Object clone() throws CloneNotSupportedException {
2619

    
2620
        DataStoreParameters dsp = getParameters();
2621

    
2622
        DefaultFeatureStore cloned_store = null;
2623

    
2624
        try {
2625
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2626
                openStore(this.getProviderName(), dsp);
2627
            if (transforms != null) {
2628
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2629
                cloned_store.transforms.setStoreForClone(cloned_store);
2630
            }
2631
        } catch (Exception e) {
2632
            throw new CloneException(e);
2633
        }
2634
        return cloned_store;
2635

    
2636
    }
2637

    
2638
    @Override
2639
    public Feature getFeature(DynObject dynobject) {
2640
        if (dynobject instanceof DynObjectFeatureFacade){
2641
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2642
            return f;
2643
        }
2644
        return null;
2645
    }
2646

    
2647
    @Override
2648
    public Iterator iterator() {
2649
        try {
2650
            return this.getFeatureSet().fastIterator();
2651
        } catch (DataException ex) {
2652
            throw new RuntimeException(ex);
2653
        }
2654
    }
2655

    
2656
    @Override
2657
    public ExpressionBuilder createExpressionBuilder() {
2658
        if( this.provider instanceof FeatureStoreProvider_v2 ) {
2659
            return ((FeatureStoreProvider_v2)this.provider).createExpression();
2660
        }
2661
        return new SQLBuilderBase();
2662
    }
2663

    
2664
    @Override
2665
    public ExpressionBuilder createExpression() {
2666
        return createExpressionBuilder();
2667
    }
2668

    
2669
    public FeatureSet features() throws DataException {
2670
        // This is to avoid jython to create a property with this name
2671
        // to access method getFeatures.
2672
        return this.getFeatureSet();
2673
    }
2674

    
2675
    @Override
2676
    public DataStoreProviderFactory getProviderFactory() {
2677
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
2678
        return factory;
2679
    }
2680

    
2681
    @Override
2682
    public void useCache(String providerName, DynObject parameters) throws DataException {
2683
        throw new UnsupportedOperationException();
2684
    }
2685

    
2686
    @Override
2687
    public boolean isBroken() {
2688
        return this.state.isBroken();
2689
    }
2690

    
2691
    @Override
2692
    public Throwable getBreakingsCause() {
2693
            return this.state.getBreakingsCause();
2694
    }
2695

    
2696
    @Override
2697
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
2698
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
2699
      if( !factory.supportNumericOID() ) {
2700
          return null;
2701
      }
2702
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
2703
      return wrappedIndex;
2704
  }
2705

    
2706
    @Override
2707
    public FeatureReference getFeatureReference(String code) {
2708
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
2709
        return featureReference;
2710
    }
2711
}