Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-2018a / 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 @ 43888

History | View | Annotate | Download (90 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
    
186
    /*
187
    TODO: Sustituir estos tres manager por un EditingManager
188
    */
189
    private FeatureTypeManager featureTypeManager;
190
    private FeatureManager featureManager;
191
    private SpatialManager spatialManager;
192

    
193
    private FeatureType defaultFeatureType = null;
194
    private List featureTypes = new ArrayList();
195

    
196
    private int mode = MODE_QUERY;
197
    private long versionOfUpdate = 0;
198
    private boolean hasStrongChanges = true;
199
    private boolean hasInserts = true;
200

    
201
    private DefaultDataManager dataManager = null;
202

    
203
    private FeatureStoreProvider provider = null;
204

    
205
    private DefaultFeatureIndexes indexes;
206

    
207
    private DefaultFeatureStoreTransforms transforms;
208

    
209
    DelegatedDynObject metadata;
210

    
211
    private Set metadataChildren;
212

    
213
    private Long featureCount = null;
214

    
215
    private long temporalOid = 0;
216

    
217
    private FeatureCacheProvider cache;
218

    
219
    StateInformation state;
220

    
221
    FeatureStoreTimeSupport timeSupport;
222

    
223

    
224
    private class StateInformation extends HashMap<Object, Object> {
225

    
226
        private static final long serialVersionUID = 4109026189635185666L;
227

    
228
        private boolean broken;
229
        private Throwable breakingsCause;
230

    
231
        @SuppressWarnings("OverridableMethodCallInConstructor")
232
        public StateInformation() {
233
            this.clear();
234
        }
235

    
236
        @Override
237
        public void clear() {
238
            this.broken = false;
239
            this.breakingsCause = null;
240
            super.clear();
241
        }
242

    
243
        public boolean isBroken() {
244
            return this.broken;
245
        }
246

    
247
        public void broken() {
248
            this.broken = true;
249
        }
250

    
251
        public Throwable getBreakingsCause() {
252
            return this.breakingsCause;
253
        }
254

    
255
        public void setBreakingsCause(Throwable cause) {
256
            if( this.breakingsCause==null ) {
257
                this.breakingsCause = cause;
258
            }
259
            this.broken = true;
260
        }
261
    }
262

    
263

    
264

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

    
274
    public DefaultFeatureStore() {
275
        this.state = new StateInformation();
276
    }
277

    
278
    @Override
279
    public void intialize(DataManager dataManager,
280
        DataStoreParameters parameters) throws InitializeException {
281

    
282
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
283

    
284
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
285
            FeatureStore.METADATA_DEFINITION_NAME,
286
            MetadataManager.METADATA_NAMESPACE
287
        );
288

    
289
        this.dataManager = (DefaultDataManager) dataManager;
290

    
291
        this.parameters = parameters;
292
        this.transforms = new DefaultFeatureStoreTransforms(this);
293
        try {
294
            indexes = new DefaultFeatureIndexes(this);
295
        } catch (DataException e) {
296
            throw new InitializeException(e);
297
        }
298

    
299
    }
300

    
301
    @Override
302
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
303
        this.provider = (FeatureStoreProvider) provider;
304
        // FIXME: habr?a que hacer un bind del provider y a?adir un dispose en el openStore del DataManager
305
        // DisposeUtils.bind(this.provider);
306

    
307
        this.delegate((DynObject) provider);
308
        this.metadataChildren = new HashSet();
309
        this.metadataChildren.add(provider);
310
    }
311

    
312
    @Override
313
    public DataStoreParameters getParameters() {
314
        return parameters;
315
    }
316

    
317
    public int getMode() {
318
        return this.mode;
319
    }
320

    
321
    @Override
322
    public DataManager getManager() {
323
        return this.dataManager;
324
    }
325

    
326
    @Override
327
    public Iterator getChildren() {
328
        return this.provider.getChilds();
329
    }
330

    
331
    @Override
332
    public FeatureStoreProvider getProvider() {
333
        return this.provider;
334
    }
335

    
336
    public FeatureManager getFeatureManager() {
337
        return this.featureManager;
338
    }
339

    
340
    @Override
341
    public void setFeatureTypes(List types, FeatureType defaultType) {
342
        this.featureTypes = types;
343
        this.defaultFeatureType = defaultType;
344
    }
345

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

    
360
    @Override
361
    public void refresh() throws OpenException, InitializeException {
362
        if (this.mode != MODE_QUERY) {
363
            throw new IllegalStateException();
364
        }
365
        this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH);
366
        if( state.isBroken() ) {
367
            this.load(state);
368
        } else {
369
            this.featureCount = null;
370
            this.provider.refresh();
371
        }
372
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
373
    }
374

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

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

    
416
        if (this.featureTypeManager != null) {
417
            this.featureTypeManager.dispose();
418
            this.featureTypeManager = null;
419
        }
420

    
421
        this.featureManager = null;
422
        this.spatialManager = null;
423

    
424
        this.parameters = null;
425
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
426
        if (delegateObservable != null) {
427
            this.delegateObservable.deleteObservers();
428
            this.delegateObservable = null;
429
        }
430
    }
431

    
432
    @Override
433
    public boolean allowWrite() {
434
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
435
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
436
            return false;
437
        }
438
        return this.provider.allowWrite();
439
    }
440

    
441
    @Override
442
    public boolean canWriteGeometry(int geometryType) throws DataException {
443
        return this.provider.canWriteGeometry(geometryType, 0);
444
    }
445

    
446
    @Override
447
    public DataServerExplorer getExplorer() throws ReadException,
448
        ValidateDataParametersException {
449
        if( this.state.isBroken() ) {
450
            try {
451
                return this.provider.getExplorer();
452
            } catch(Throwable th) {
453
                return null;
454
            }
455
        } else {
456
            return this.provider.getExplorer();
457
        }
458
    }
459

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

    
472
    @Override
473
    public Envelope getEnvelope() throws DataException {
474
        if (this.mode == MODE_FULLEDIT) {
475
                // Just in case another thread tries to write in the store
476
                synchronized (this) {
477
                        return this.spatialManager.getEnvelope();
478
                        }
479
        }
480
        if (hasDynValue(DataStore.METADATA_ENVELOPE)){
481
            return (Envelope)getDynValue(DataStore.METADATA_ENVELOPE);
482
        }
483
        return this.provider.getEnvelope();
484
    }
485

    
486
    /**
487
     * @throws org.gvsig.fmap.dal.exception.DataException
488
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
489
     */
490
    @Override
491
    public IProjection getSRSDefaultGeometry() throws DataException {
492
        return this.getDefaultFeatureType().getDefaultSRS();
493
    }
494

    
495
    @Override
496
    public FeatureSelection createDefaultFeatureSelection()
497
        throws DataException {
498
        return new DefaultFeatureSelection(this);
499
    }
500

    
501
    @Override
502
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
503
        throws DataException {
504
        if (type.hasOID()) {
505
            return new DefaultFeatureProvider(type,
506
                this.provider.createNewOID());
507
        }
508
        return new DefaultFeatureProvider(type);
509
    }
510

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

    
546
        }
547

    
548
        if (evaluatedAttr.isEmpty()) {
549
            evaluatedAttr = null;
550
        }
551

    
552
        state.set("evaluatedAttributes", evaluatedAttr);
553
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
554

    
555
    }
556

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

    
595
    private void load(StateInformation state) {
596
        this.featureTypes = new ArrayList();
597
        this.defaultFeatureType = null;
598
        this.featureCount = null;
599

    
600
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
601
        try {
602
            intialize(dataManager, params);
603
        } catch(Throwable th) {
604
            state.setBreakingsCause(th);
605
        }
606

    
607
        try {
608
            DataStoreProvider prov = dataManager.createProvider(
609
                getStoreProviderServices(),
610
                params
611
            );
612
            setProvider(prov);
613
        } catch(Throwable th) {
614
            state.setBreakingsCause(th);
615
        }
616

    
617
        try {
618
            selection = (FeatureSelection) state.get("selection");
619
        } catch(Throwable th) {
620
            state.setBreakingsCause(th);
621
        }
622

    
623
        try {
624
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
625
            this.transforms.setFeatureStore(this);
626
            for( FeatureStoreTransform transform : this.transforms ) {
627
                try {
628
                    transform.setUp();
629
                } catch(Throwable th) {
630
                    state.setBreakingsCause(th);
631
                }
632
            }
633
        } catch(Throwable th) {
634
            state.setBreakingsCause(th);
635
        }
636

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

    
668
                    }
669

    
670
            }
671
        } catch(Throwable th) {
672
            state.setBreakingsCause(th);
673
        }
674

    
675

    
676
        try {
677
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
678
            FeatureType ftype;
679

    
680
            if (defaultFeatureType == null ||
681
                    defaultFeatureType.getId() == null ||
682
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
683

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

    
703
        LOG.info("load() broken:{}, {}, {}.",
704
                new Object[] { state.isBroken(), this.getProviderName(), params }
705
        );
706
    }
707

    
708
        public DataStoreProviderServices getStoreProviderServices() {
709
                return this;
710
        }
711

    
712
    public static void registerPersistenceDefinition() {
713
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
714
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
715
            DynStruct definition =
716
                manager.addDefinition(DefaultFeatureStore.class,
717
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
718
                        + " Persistent definition", null, null);
719
            definition.addDynFieldString("dataStoreName").setMandatory(true)
720
                .setPersistent(true);
721

    
722
            definition.addDynFieldObject("parameters")
723
                .setClassOfValue(DynObject.class).setMandatory(true)
724
                .setPersistent(true);
725

    
726
            definition.addDynFieldObject("selection")
727
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
728
                .setPersistent(true);
729

    
730
            definition.addDynFieldObject("transforms")
731
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
732
                .setMandatory(true).setPersistent(true);
733

    
734
            definition.addDynFieldMap("evaluatedAttributes")
735
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
736
                .setMandatory(false).setPersistent(true);
737

    
738
            definition.addDynFieldString("defaultFeatureTypeId")
739
                .setMandatory(true).setPersistent(true);
740
        }
741
    }
742

    
743
    public static void registerMetadataDefinition() throws MetadataException {
744
        MetadataManager manager = MetadataLocator.getMetadataManager();
745
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
746
            DynStruct metadataDefinition =
747
                manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
748
            metadataDefinition.extend(manager
749
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
750
        }
751
    }
752

    
753
    //
754
    // ====================================================================
755
    // Gestion de la seleccion
756
    //
757

    
758
    @Override
759
    public void setSelection(DataSet selection) throws DataException {
760
        this.setSelection((FeatureSet) selection);
761
    }
762

    
763
    @Override
764
    public DataSet createSelection() throws DataException {
765
        return createFeatureSelection();
766
    }
767

    
768
    @Override
769
    public DataSet getSelection() throws DataException {
770
        return this.getFeatureSelection();
771
    }
772

    
773
    @Override
774
    public void setSelection(FeatureSet selection) throws DataException {
775
        setSelection(selection, true);
776
    }
777

    
778
    public void setSelection(FeatureSet selection, boolean undoable)
779
        throws DataException {
780
        if (selection == null) {
781
            if (undoable) {
782
                throw new SelectionNotAllowedException(getName());
783
            }
784

    
785
        } else {
786
            if (selection.equals(this.selection)) {
787
                return;
788
            }
789
            if (!selection.isFromStore(this)) {
790
                throw new SelectionNotAllowedException(getName());
791
            }
792
        }
793

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

    
832
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
833
    }
834

    
835
    @Override
836
    public FeatureSelection createFeatureSelection() throws DataException {
837
        return this.provider.createFeatureSelection();
838
    }
839

    
840
    @Override
841
    public FeatureSelection getFeatureSelection() throws DataException {
842
        if (selection == null) {
843
            this.selection = createFeatureSelection();
844
            this.selection.addObserver(this);
845
        }
846
        return selection;
847
    }
848

    
849
    //
850
    // ====================================================================
851
    // Gestion de notificaciones
852
    //
853

    
854
    @Override
855
    public void notifyChange(FeatureStoreNotification storeNotification) {
856
        try {
857
            delegateObservable.notifyObservers(storeNotification);
858
        } catch (Throwable ex) {
859
            LOG.warn("Problems notifying changes in the store '"+this.getName()+" ("+storeNotification.getType()+").",ex);
860
        }
861
    }
862

    
863
    @Override
864
    public void notifyChange(String notification) {
865
        if (delegateObservable != null) {
866
            notifyChange(new DefaultFeatureStoreNotification(this, notification));
867
        }
868

    
869
    }
870

    
871
    @Override
872
    public void notifyChange(String notification, FeatureProvider data) {
873
        Feature f = null;
874
        try {
875
            f = createFeature(data);
876
        } catch (Throwable ex) {
877
            LOG.warn("Problems creating a feature to notifying changes in the store '"+this.getName()+" ("+notification+").",ex);
878
        }
879
        notifyChange(notification, f);
880
    }
881

    
882
    public void notifyChange(String notification, Feature feature) {
883
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
884
            feature));
885
    }
886

    
887
    public void notifyChange(String notification, Command command) {
888
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
889
            command));
890
    }
891

    
892
    public void notifyChange(String notification, EditableFeatureType type) {
893
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
894
            type));
895
    }
896

    
897
    @Override
898
    public void notifyChange(String notification, Resource resource) {
899
        notifyChange(new DefaultFeatureStoreNotification(this,
900
            DataStoreNotification.RESOURCE_CHANGED));
901
    }
902

    
903
    //
904
    // ====================================================================
905
    // Gestion de bloqueos
906
    //
907

    
908
    @Override
909
    public boolean isLocksSupported() {
910
        return this.provider.isLocksSupported();
911
    }
912

    
913
    @Override
914
    public FeatureLocks getLocks() throws DataException {
915
        if (!this.provider.isLocksSupported()) {
916
            LOG.warn("Locks not supported");
917
            return null;
918
        }
919
        if (locks == null) {
920
            this.locks = this.provider.createFeatureLocks();
921
        }
922
        return locks;
923
    }
924

    
925
    //
926
    // ====================================================================
927
    // Interface Observable
928
    //
929

    
930
    @Override
931
    public void disableNotifications() {
932
        this.delegateObservable.disableNotifications();
933

    
934
    }
935

    
936
    @Override
937
    public void enableNotifications() {
938
        this.delegateObservable.enableNotifications();
939
    }
940

    
941
    @Override
942
    public void beginComplexNotification() {
943
        this.delegateObservable.beginComplexNotification();
944

    
945
    }
946

    
947
    @Override
948
    public void endComplexNotification() {
949
        this.delegateObservable.endComplexNotification();
950

    
951
    }
952

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

    
960
    @Override
961
    public void deleteObserver(Observer observer) {
962
        if (delegateObservable != null) {
963
            this.delegateObservable.deleteObserver(observer);
964
        }
965
    }
966

    
967
    @Override
968
    public void deleteObservers() {
969
        this.delegateObservable.deleteObservers();
970

    
971
    }
972

    
973
    //
974
    // ====================================================================
975
    // Interface Observer
976
    //
977
    // Usado para observar:
978
    // - su seleccion
979
    // - sus bloqueos
980
    // - sus recursos
981
    //
982

    
983
    @Override
984
    public void update(Observable observable, Object notification) {
985
        if (observable instanceof FeatureSet) {
986
            if (observable == this.selection) {
987
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
988
            } else if (observable == this.locks) {
989
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
990
            }
991

    
992
        } else if (observable instanceof FeatureStoreProvider) {
993
            if (observable == this.provider) {
994

    
995
            }
996
        } else if (observable instanceof FeatureReferenceSelection) {
997
            if(notification instanceof String){
998
                    this.notifyChange((String)notification);
999
            }
1000
        }
1001
    }
1002

    
1003
    //
1004
    // ====================================================================
1005
    // Edicion
1006
    //
1007

    
1008
    private void newVersionOfUpdate() {
1009
        this.versionOfUpdate++;
1010
    }
1011

    
1012
    private long currentVersionOfUpdate() {
1013
        return this.versionOfUpdate;
1014
    }
1015

    
1016
    private void checkInEditingMode() throws NeedEditingModeException {
1017
        if (mode != MODE_FULLEDIT) {
1018
            throw new NeedEditingModeException(this.getName());
1019
        }
1020
    }
1021

    
1022
    private void checkNotInAppendMode() throws IllegalStateException {
1023
        if (mode == MODE_APPEND) {
1024
                        throw new IllegalStateException("Error: store "
1025
                                        + this.getFullName() + " is in append mode");
1026
        }
1027
    }
1028

    
1029
    private void checkIsOwnFeature(Feature feature)
1030
        throws IllegalFeatureException {
1031
        if (((DefaultFeature) feature).getStore() != this) {
1032
            throw new IllegalFeatureException(this.getName());
1033
        }
1034
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1035
        // fixFeatureType((DefaultFeatureType) feature.getType());
1036
    }
1037

    
1038
    private void exitEditingMode() {
1039
        if (commands != null) {
1040
            commands.clear();
1041
            commands = null;
1042
        }
1043

    
1044
        if (featureTypeManager != null) {
1045
            featureTypeManager.dispose();
1046
            featureTypeManager = null;
1047

    
1048
        }
1049

    
1050
        // TODO implementar un dispose para estos dos
1051
        featureManager = null;
1052
        spatialManager = null;
1053

    
1054
        featureCount = null;
1055

    
1056
        mode = MODE_QUERY;
1057
        hasStrongChanges = true; // Lo deja a true por si las moscas
1058
        hasInserts = true;
1059
    }
1060

    
1061
    @Override
1062
    synchronized public void edit() throws DataException {
1063
        edit(MODE_FULLEDIT);
1064
    }
1065

    
1066
    @Override
1067
    synchronized public void edit(int mode) throws DataException {
1068
        LOG.debug("Starting editing in mode: {}", mode);
1069
        try {
1070
            if (this.mode != MODE_QUERY) {
1071
                throw new AlreadyEditingException(this.getName());
1072
            }
1073
            if (!this.provider.supportsAppendMode()) {
1074
                mode = MODE_FULLEDIT;
1075
            }
1076
            switch (mode) {
1077
            case MODE_QUERY:
1078
                throw new IllegalStateException(this.getName());
1079

    
1080
            case MODE_FULLEDIT:
1081
                if (!this.transforms.isEmpty()) {
1082
                    throw new IllegalStateException(this.getName());
1083
                }
1084
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
1085
                invalidateIndexes();
1086
                featureManager = new FeatureManager();
1087
                featureTypeManager = new FeatureTypeManager(this);
1088
                spatialManager = new SpatialManager(this, provider.getEnvelope());
1089

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

    
1115
    private void invalidateIndexes() {
1116
        setIndexesValidStatus(false);
1117
    }
1118

    
1119
    private void setIndexesValidStatus(boolean valid) {
1120
        FeatureIndexes theIndexes = getIndexes();
1121
        LOG.debug("Setting the store indexes to valid status {}: {}", (valid
1122
            ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1123
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1124
            FeatureIndex index = (FeatureIndex) iterator.next();
1125
            if (index instanceof FeatureIndexProviderServices) {
1126
                FeatureIndexProviderServices indexServices =
1127
                    (FeatureIndexProviderServices) index;
1128
                indexServices.setValid(valid);
1129
            }
1130
        }
1131
    }
1132

    
1133
    private void updateIndexes() throws FeatureIndexException {
1134
        FeatureIndexes theIndexes = getIndexes();
1135
        LOG.debug("Refilling indexes: {}", theIndexes);
1136
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1137
            FeatureIndex index = (FeatureIndex) iterator.next();
1138
            if (index instanceof FeatureIndexProviderServices) {
1139
                FeatureIndexProviderServices indexServices =
1140
                    (FeatureIndexProviderServices) index;
1141
                indexServices.fill(true, null);
1142
            }
1143
        }
1144
    }
1145

    
1146
    private void waitForIndexes() {
1147
        FeatureIndexes theIndexes = getIndexes();
1148
        LOG.debug("Waiting for indexes to finish filling: {}", theIndexes);
1149
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1150
            FeatureIndex index = (FeatureIndex) iterator.next();
1151
            if (index instanceof FeatureIndexProviderServices) {
1152
                FeatureIndexProviderServices indexServices =
1153
                    (FeatureIndexProviderServices) index;
1154
                indexServices.waitForIndex();
1155
            }
1156
        }
1157
    }
1158

    
1159
    private void disposeIndexes() {
1160
        FeatureIndexes theIndexes = getIndexes();
1161
        LOG.debug("Disposing indexes: {}", theIndexes);
1162
        if( theIndexes==null ) {
1163
            return;
1164
        }
1165
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1166
            FeatureIndex index = (FeatureIndex) iterator.next();
1167
            if (index instanceof FeatureIndexProviderServices) {
1168
                FeatureIndexProviderServices indexServices =
1169
                    (FeatureIndexProviderServices) index;
1170
                indexServices.dispose();
1171
            }
1172
        }
1173
    }
1174

    
1175
    @Override
1176
    public boolean isEditing() {
1177
        return mode == MODE_FULLEDIT;
1178
    }
1179

    
1180
    @Override
1181
    public boolean isAppending() {
1182
        return mode == MODE_APPEND;
1183
    }
1184

    
1185
    @Override
1186
    synchronized public void update(EditableFeatureType type)
1187
        throws DataException {
1188
        try {
1189
            checkInEditingMode();
1190
            if (type == null) {
1191
                throw new NullFeatureTypeException(getName());
1192
            }
1193
            // FIXME: Comprobar que es un featureType aceptable.
1194
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
1195
            newVersionOfUpdate();
1196

    
1197
            FeatureType oldt = type.getSource().getCopy();
1198
            FeatureType newt = type.getCopy();
1199
            commands.update(newt, oldt);
1200

    
1201
            if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
1202
                hasStrongChanges = true;
1203
            }
1204
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1205
        } catch (Exception e) {
1206
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1207
        }
1208
    }
1209

    
1210
    @Override
1211
    public void delete(Feature feature) throws DataException {
1212
        this.commands.delete(feature);
1213
    }
1214

    
1215
    synchronized public void doDelete(Feature feature) throws DataException {
1216
        try {
1217
            checkInEditingMode();
1218
            checkIsOwnFeature(feature);
1219
            if (feature instanceof EditableFeature) {
1220
                throw new StoreDeleteEditableFeatureException(getName());
1221
            }
1222
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1223

    
1224
            //Update the featureManager and the spatialManager
1225
            featureManager.delete(feature.getReference());
1226
            spatialManager.deleteFeature(feature);
1227

    
1228
            newVersionOfUpdate();
1229
            hasStrongChanges = true;
1230
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1231
        } catch (Exception e) {
1232
            throw new StoreDeleteFeatureException(e, this.getName());
1233
        }
1234
    }
1235

    
1236
    private static EditableFeature lastChangedFeature = null;
1237

    
1238
    @Override
1239
    public synchronized void insert(EditableFeature feature)
1240
        throws DataException {
1241
        LOG.debug("In editing mode {}, insert feature: {}", mode, feature);
1242
        try {
1243
            switch (mode) {
1244
            case MODE_QUERY:
1245
                throw new NeedEditingModeException(this.getName());
1246

    
1247
            case MODE_APPEND:
1248
                checkIsOwnFeature(feature);
1249
                if (feature.getSource() != null) {
1250
                    throw new NoNewFeatureInsertException(this.getName());
1251
                }
1252
                this.featureCount = null;
1253
                notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1254
                feature.validate(Feature.UPDATE);
1255
                provider.append(((DefaultEditableFeature) feature).getData());
1256
                hasStrongChanges = true;
1257
                hasInserts = true;
1258
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1259
                break;
1260

    
1261
            case MODE_FULLEDIT:
1262
                if (feature.getSource() != null) {
1263
                    throw new NoNewFeatureInsertException(this.getName());
1264
                }
1265
                commands.insert(feature);
1266
            }
1267
        } catch (Exception e) {
1268
            throw new StoreInsertFeatureException(e, this.getName());
1269
        }
1270
    }
1271

    
1272
    synchronized public void doInsert(EditableFeature feature)
1273
        throws DataException {
1274
        checkIsOwnFeature(feature);
1275

    
1276
        waitForIndexes();
1277

    
1278
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1279
        newVersionOfUpdate();
1280
        if ((lastChangedFeature == null)
1281
            || (lastChangedFeature.getSource() != feature.getSource())) {
1282
            lastChangedFeature = feature;
1283
            feature.validate(Feature.UPDATE);
1284
            lastChangedFeature = null;
1285
        }
1286
        //Update the featureManager and the spatialManager
1287
        ((DefaultEditableFeature) feature).setInserted(true);
1288
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1289

    
1290

    
1291
        featureManager.add(newFeature);
1292
        spatialManager.insertFeature(newFeature);
1293

    
1294
        hasStrongChanges = true;
1295
        hasInserts = true;
1296
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1297
    }
1298

    
1299
    @Override
1300
    public void update(EditableFeature feature)
1301
    throws DataException {
1302
        if ((feature).getSource() == null) {
1303
            insert(feature);
1304
            return;
1305
        }
1306
        commands.update(feature, feature.getSource());
1307
    }
1308

    
1309
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1310
        throws DataException {
1311
        try {
1312
            checkInEditingMode();
1313
            checkIsOwnFeature(feature);
1314
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature);
1315
            newVersionOfUpdate();
1316
            if ((lastChangedFeature == null)
1317
                || (lastChangedFeature.getSource() != feature.getSource())) {
1318
                lastChangedFeature = feature;
1319
                feature.validate(Feature.UPDATE);
1320
                lastChangedFeature = null;
1321
            }
1322

    
1323
            //Update the featureManager and the spatialManager
1324
            Feature newf = feature.getNotEditableCopy();
1325
            featureManager.update(newf, oldFeature);
1326
            spatialManager.updateFeature(newf, oldFeature);
1327

    
1328
            hasStrongChanges = true;
1329
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1330
        } catch (Exception e) {
1331
            throw new StoreUpdateFeatureException(e, this.getName());
1332
        }
1333
    }
1334

    
1335
    @Override
1336
    synchronized public void redo() throws RedoException {
1337
        Command redo = commands.getNextRedoCommand();
1338
        try {
1339
            checkInEditingMode();
1340
        } catch (NeedEditingModeException ex) {
1341
            throw new RedoException(redo, ex);
1342
        }
1343
        notifyChange(FeatureStoreNotification.BEFORE_REDO, redo);
1344
        newVersionOfUpdate();
1345
        commands.redo();
1346
        hasStrongChanges = true;
1347
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1348
    }
1349

    
1350
    @Override
1351
    synchronized public void undo() throws UndoException {
1352
        Command undo = commands.getNextUndoCommand();
1353
        try {
1354
            checkInEditingMode();
1355
        } catch (NeedEditingModeException ex) {
1356
            throw new UndoException(undo, ex);
1357
        }
1358
        notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo);
1359
        newVersionOfUpdate();
1360
        commands.undo();
1361
        hasStrongChanges = true;
1362
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1363
    }
1364

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

    
1374
    @Override
1375
    public List getUndoInfos() {
1376
        if (isEditing() && (commands != null)) {
1377
            return commands.getUndoInfos();
1378
        } else {
1379
            return null;
1380
        }
1381
    }
1382

    
1383
    public synchronized FeatureCommandsStack getCommandsStack()
1384
        throws DataException {
1385
        checkInEditingMode();
1386
        return commands;
1387
    }
1388

    
1389
    @Override
1390
    synchronized public void cancelEditing() throws DataException {
1391
        if( spatialManager!=null ) {
1392
            spatialManager.cancelModifies();
1393
        }
1394
        try {
1395
            switch (mode) {
1396
            case MODE_QUERY:
1397
                throw new NeedEditingModeException(this.getName());
1398

    
1399
            case MODE_APPEND:
1400
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1401
                provider.abortAppend();
1402
                exitEditingMode();
1403
                ((FeatureSelection) this.getSelection()).deselectAll();
1404
                updateIndexes();
1405
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1406

    
1407
            case MODE_FULLEDIT:
1408
                boolean clearSelection = this.hasStrongChanges;
1409
                if (this.selection instanceof FeatureReferenceSelection) {
1410
                    clearSelection = this.hasInserts;
1411
                }
1412
                notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1413
                exitEditingMode();
1414
                if (clearSelection) {
1415
                    ((FeatureSelection) this.getSelection()).deselectAll();
1416
                }
1417
                updateIndexes();
1418
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1419
            }
1420
        } catch (Exception e) {
1421
            throw new StoreCancelEditingException(e, this.getName());
1422
        }
1423
    }
1424

    
1425
    @Override
1426
    synchronized public void finishEditing() throws DataException {
1427
        LOG.debug("finish editing of mode: {}", mode);
1428
        try {
1429

    
1430
            /*
1431
             * Selection needs to be cleared when editing stops
1432
             * to prevent conflicts with selection remaining from
1433
             * editing mode.
1434
             */
1435
//            ((FeatureSelection) this.getSelection()).deselectAll();
1436

    
1437
            switch (mode) {
1438
            case MODE_QUERY:
1439
                throw new NeedEditingModeException(this.getName());
1440

    
1441
            case MODE_APPEND:
1442
                if( selection!=null ) {
1443
                    selection = null;
1444
                }
1445
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1446
                provider.endAppend();
1447
                exitEditingMode();
1448
                updateIndexes();
1449
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1450
                break;
1451

    
1452
            case MODE_FULLEDIT:
1453
                if (hasStrongChanges && !this.allowWrite()) {
1454
                    throw new WriteNotAllowedException(getName());
1455
                }
1456
                if(featureManager.isSelectionCompromised() && selection!=null ) {
1457
                    selection = null;
1458
                }
1459
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1460
                if (hasStrongChanges) {
1461
                    validateFeatures(Feature.FINISH_EDITING);
1462

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

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

    
1503
        case MODE_APPEND:
1504
          this.provider.endAppend();
1505
          exitEditingMode();
1506
          invalidateIndexes();
1507
          this.provider.beginAppend();
1508
          hasInserts = false;
1509
          break;
1510

    
1511
        case MODE_FULLEDIT:
1512
          if (hasStrongChanges && !this.allowWrite()) {
1513
            throw new WriteNotAllowedException(getName());
1514
          }
1515
          if (hasStrongChanges) {
1516
            validateFeatures(Feature.FINISH_EDITING);
1517
            provider.performChanges(featureManager.getDeleted(),
1518
              featureManager.getInserted(),
1519
              featureManager.getUpdated(),
1520
              featureTypeManager.getFeatureTypesChanged());
1521
          }
1522
          invalidateIndexes();
1523
          featureManager = new FeatureManager();
1524
          featureTypeManager = new FeatureTypeManager(this);
1525
          spatialManager = new SpatialManager(this, provider.getEnvelope());
1526

    
1527
          commands =
1528
            new DefaultFeatureCommandsStack(this, featureManager,
1529
              spatialManager, featureTypeManager);
1530
          featureCount = null;
1531
          hasStrongChanges = false;
1532
          hasInserts = false;
1533
          break;
1534
        }
1535
      } catch (Exception e) {
1536
        throw new FinishEditingException(e);
1537
      }
1538
    }
1539

    
1540
    @Override
1541
    synchronized public boolean canCommitChanges() throws DataException {
1542
        if ( !this.allowWrite()) {
1543
                return false;
1544
        }
1545
            switch (mode) {
1546
            default:
1547
        case MODE_QUERY:
1548
                return false;
1549

    
1550
        case MODE_APPEND:
1551
                return true;
1552

    
1553
        case MODE_FULLEDIT:
1554
            List types = this.getFeatureTypes();
1555
            for( int i=0; i<types.size(); i++ ) {
1556
                    Object type = types.get(i);
1557
                    if( type instanceof DefaultEditableFeatureType ) {
1558
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1559
                                    return false;
1560
                            }
1561
                    }
1562
            }
1563
            return true;
1564
            }
1565
    }
1566

    
1567
    @Override
1568
    public void beginEditingGroup(String description)
1569
        throws NeedEditingModeException {
1570
        checkInEditingMode();
1571
        commands.startComplex(description);
1572
    }
1573

    
1574
    @Override
1575
    public void endEditingGroup() throws NeedEditingModeException {
1576
        checkInEditingMode();
1577
        commands.endComplex();
1578
    }
1579

    
1580
    @Override
1581
    public boolean isAppendModeSupported() {
1582
        return this.provider.supportsAppendMode();
1583
    }
1584

    
1585
    @Override
1586
    public void export(DataServerExplorer explorer, String provider,
1587
        NewFeatureStoreParameters params) throws DataException {
1588

    
1589
        if (this.getFeatureTypes().size() != 1) {
1590
            throw new NotYetImplemented(
1591
                "export whith more than one type not yet implemented");
1592
        }
1593
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1594
        FeatureStore target = null;
1595
        FeatureSet features = null;
1596
        DisposableIterator iterator = null;
1597
        try {
1598
            FeatureType type = this.getDefaultFeatureType();
1599
            if ((params.getDefaultFeatureType() == null)
1600
                || (params.getDefaultFeatureType().size() == 0)) {
1601
                params.setDefaultFeatureType(type.getEditable());
1602

    
1603
            }
1604
            explorer.add(provider, params, true);
1605

    
1606
            DataManager manager = DALLocator.getDataManager();
1607
            target = (FeatureStore) manager.openStore(provider, params);
1608
            FeatureType targetType = target.getDefaultFeatureType();
1609

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

    
1641
    //
1642
    // ====================================================================
1643
    // Obtencion de datos
1644
    // getDataCollection, getFeatureCollection
1645
    //
1646

    
1647
    @Override
1648
    public DataSet getDataSet() throws DataException {
1649
        checkNotInAppendMode();
1650
        FeatureQuery query =
1651
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1652
        return new DefaultFeatureSet(this, query);
1653
    }
1654

    
1655
    @Override
1656
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1657
        checkNotInAppendMode();
1658
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1659
    }
1660

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

    
1667
    @Override
1668
    public void getDataSet(DataQuery dataQuery, Observer observer)
1669
        throws DataException {
1670
        checkNotInAppendMode();
1671
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1672
    }
1673

    
1674
    @Override
1675
    public FeatureSet getFeatureSet() throws DataException {
1676
        return this.getFeatureSet((FeatureQuery)null);
1677
    }
1678

    
1679
    @Override
1680
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1681
        throws DataException {
1682
        checkNotInAppendMode();
1683
        if( featureQuery==null ) {
1684
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1685
        }
1686
        return new DefaultFeatureSet(this, featureQuery);
1687
    }
1688

    
1689
    @Override
1690
    public FeatureSet getFeatureSet(String filter) throws DataException {
1691
        return this.getFeatureSet(filter, null, true);
1692
    }
1693

    
1694
    @Override
1695
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
1696
        return this.getFeatureSet(filter, sortBy, true);
1697
    }
1698

    
1699
    @Override
1700
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
1701
        FeatureQuery query = this.createFeatureQuery();
1702
        if( !StringUtils.isEmpty(filter) ) {
1703
            query.setFilter(filter);
1704
        }
1705
        if( !StringUtils.isEmpty(sortBy) ) {
1706
            query.getOrder().add(sortBy, asc);
1707
        }
1708
        return this.getFeatureSet(query);
1709
    }
1710

    
1711
    @Override
1712
    public List<Feature> getFeatures(String filter)  {
1713
        return this.getFeatures(filter, null, true);
1714
    }
1715

    
1716
    @Override
1717
    public List<Feature> getFeatures(String filter, String sortBy)  {
1718
        return this.getFeatures(filter, sortBy, true);
1719
    }
1720

    
1721
    @Override
1722
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
1723
        FeatureQuery query = this.createFeatureQuery();
1724
        if( !StringUtils.isEmpty(filter) ) {
1725
            query.setFilter(filter);
1726
        }
1727
        if( !StringUtils.isEmpty(sortBy) ) {
1728
            query.getOrder().add(sortBy, asc);
1729
        }
1730
        return this.getFeatures(query, 100);
1731
    }
1732

    
1733
    @Override
1734
    public List<Feature> getFeatures(FeatureQuery query)  {
1735
        return this.getFeatures(query, 100);
1736
    }
1737

    
1738
    @Override
1739
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
1740
        try {
1741
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
1742
            return pager.asList();
1743
        } catch (BaseException ex) {
1744
            throw new RuntimeException("Can't create the list of features.", ex);
1745
        }
1746
    }
1747

    
1748
    @Override
1749
    public List<Feature> getFeatures() {
1750
        return this.getFeatures(null, 500);
1751
    }
1752

    
1753
    @Override
1754
    public Feature findFirst(String filter) throws DataException {
1755
        return this.findFirst(filter, null, true);
1756
    }
1757

    
1758
    @Override
1759
    public Feature findFirst(String filter, String sortBy) throws DataException {
1760
        return this.findFirst(filter, sortBy, true);
1761
    }
1762

    
1763
    @Override
1764
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
1765
        FeatureSet set = this.getFeatureSet(filter, sortBy, asc);
1766
        if( set==null || set.isEmpty() ) {
1767
            return null;
1768
        }
1769
        DisposableIterator it = set.iterator();
1770
        Feature f = (Feature) it.next();
1771
        it.dispose();
1772
        return f;
1773
    }
1774

    
1775
    @Override
1776
    public void accept(Visitor visitor) throws BaseException {
1777
        FeatureSet set = getFeatureSet();
1778
        try {
1779
            set.accept(visitor);
1780
        } finally {
1781
            set.dispose();
1782
        }
1783
    }
1784

    
1785
    @Override
1786
    public void accept(Visitor visitor, DataQuery dataQuery)
1787
        throws BaseException {
1788
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
1789
        try {
1790
            set.accept(visitor);
1791
        } finally {
1792
            set.dispose();
1793
        }
1794
    }
1795

    
1796
    public FeatureType getFeatureType(FeatureQuery featureQuery)
1797
        throws DataException {
1798
        DefaultFeatureType fType =
1799
            (DefaultFeatureType) this.getFeatureType(featureQuery
1800
                .getFeatureTypeId());
1801
        if( featureQuery.hasAttributeNames() || featureQuery.hasConstantsAttributeNames() ) {
1802
            return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames() );
1803
        }
1804
        return fType;
1805
    }
1806

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

    
1813
    @Override
1814
    public void getFeatureSet(FeatureQuery query, Observer observer)
1815
        throws DataException {
1816
        class LoadInBackGround implements Runnable {
1817

    
1818
            private final FeatureStore store;
1819
            private final FeatureQuery query;
1820
            private final Observer observer;
1821

    
1822
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
1823
                Observer observer) {
1824
                this.store = store;
1825
                this.query = query;
1826
                this.observer = observer;
1827
            }
1828

    
1829
            void notify(FeatureStoreNotification theNotification) {
1830
                observer.update(store, theNotification);
1831
            }
1832

    
1833
            @Override
1834
            public void run() {
1835
                FeatureSet set = null;
1836
                try {
1837
                    set = store.getFeatureSet(query);
1838
                    notify(new DefaultFeatureStoreNotification(store,
1839
                        FeatureStoreNotification.LOAD_FINISHED, set));
1840
                } catch (Exception e) {
1841
                    notify(new DefaultFeatureStoreNotification(store,
1842
                        FeatureStoreNotification.LOAD_FINISHED, e));
1843
                } finally {
1844
                    dispose(set);
1845
                }
1846
            }
1847
        }
1848

    
1849
        checkNotInAppendMode();
1850
        if (query == null) {
1851
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
1852
        }
1853
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
1854
        Thread thread = new Thread(task, "Load Feature Set in background");
1855
        thread.start();
1856
    }
1857

    
1858
    @Override
1859
    public Feature getFeatureByReference(FeatureReference reference)
1860
        throws DataException {
1861
        checkNotInAppendMode();
1862
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
1863
        FeatureType featureType;
1864
        if (ref.getFeatureTypeId() == null) {
1865
            featureType = this.getDefaultFeatureType();
1866
        } else {
1867
            featureType = this.getFeatureType(ref.getFeatureTypeId());
1868
        }
1869
        return this.getFeatureByReference(reference, featureType);
1870
    }
1871

    
1872
    @Override
1873
    public Feature getFeatureByReference(FeatureReference reference,
1874
        FeatureType featureType) throws DataException {
1875
        checkNotInAppendMode();
1876
        featureType = fixFeatureType((DefaultFeatureType) featureType);
1877
        if (this.mode == MODE_FULLEDIT) {
1878
            Feature f = featureManager.get(reference, this, featureType);
1879
            if (f != null) {
1880
                return f;
1881
            }
1882
        }
1883

    
1884
        FeatureType sourceFeatureType = featureType;
1885
        if (!this.transforms.isEmpty()) {
1886
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
1887
        }
1888
        // TODO comprobar que el id es de este store
1889

    
1890
        DefaultFeature feature =
1891
            new DefaultFeature(this,
1892
                this.provider.getFeatureProviderByReference(
1893
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
1894

    
1895
        if (!this.transforms.isEmpty()) {
1896
            return this.transforms.applyTransform(feature, featureType);
1897
        }
1898
        return feature;
1899
    }
1900

    
1901
    //
1902
    // ====================================================================
1903
    // Gestion de features
1904
    //
1905

    
1906
    private FeatureType fixFeatureType(DefaultFeatureType type)
1907
        throws DataException {
1908
        FeatureType original = this.getDefaultFeatureType();
1909

    
1910
        if ((type == null) || type.equals(original)) {
1911
            return original;
1912
        } else {
1913
            if (!type.isSubtypeOf(original)) {
1914
                Iterator iter = this.getFeatureTypes().iterator();
1915
                FeatureType tmpType;
1916
                boolean found = false;
1917
                while (iter.hasNext()) {
1918
                    tmpType = (FeatureType) iter.next();
1919
                    if (type.equals(tmpType)) {
1920
                        return type;
1921

    
1922
                    } else
1923
                        if (type.isSubtypeOf(tmpType)) {
1924
                            found = true;
1925
                            original = tmpType;
1926
                            break;
1927
                        }
1928

    
1929
                }
1930
                if (!found) {
1931
                    throw new IllegalFeatureTypeException(getName());
1932
                }
1933
            }
1934
        }
1935

    
1936
        // Checks that type has all fields of pk
1937
        // else add the missing attributes at the end.
1938
        if (!original.hasOID()) {
1939
            // Gets original pk attributes
1940
            DefaultEditableFeatureType edOriginal =
1941
                (DefaultEditableFeatureType) original.getEditable();
1942
            FeatureAttributeDescriptor orgAttr;
1943
            Iterator edOriginalIter = edOriginal.iterator();
1944
            while (edOriginalIter.hasNext()) {
1945
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1946
                if (!orgAttr.isPrimaryKey()) {
1947
                    edOriginalIter.remove();
1948
                }
1949
            }
1950

    
1951
            // Checks if all pk attributes are in type
1952
            Iterator typeIterator;
1953
            edOriginalIter = edOriginal.iterator();
1954
            FeatureAttributeDescriptor attr;
1955
            while (edOriginalIter.hasNext()) {
1956
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1957
                typeIterator = type.iterator();
1958
                while (typeIterator.hasNext()) {
1959
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
1960
                    if (attr.getName().equals(orgAttr.getName())) {
1961
                        edOriginalIter.remove();
1962
                        break;
1963
                    }
1964
                }
1965
            }
1966

    
1967
            // add missing pk attributes if any
1968
            if (edOriginal.size() > 0) {
1969
                boolean isEditable = type instanceof DefaultEditableFeatureType;
1970
                DefaultEditableFeatureType edType =
1971
                    (DefaultEditableFeatureType) original.getEditable();
1972
                edType.clear();
1973
                edType.addAll(type);
1974
                edType.addAll(edOriginal);
1975
                if (!isEditable) {
1976
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
1977
                }
1978
            }
1979

    
1980
        }
1981

    
1982
        return type;
1983
    }
1984

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

    
2012
    @Override
2013
    public FeatureType getDefaultFeatureType() throws DataException {
2014
        try {
2015

    
2016
            if (isEditing()) {
2017
                FeatureType auxFeatureType =
2018
                    featureTypeManager.getType(defaultFeatureType.getId());
2019
                if (auxFeatureType != null) {
2020
                    return avoidEditable(auxFeatureType);
2021
                }
2022
            }
2023
            FeatureType type = this.transforms.getDefaultFeatureType();
2024
            if (type != null) {
2025
                return avoidEditable(type);
2026
            }
2027

    
2028
            return avoidEditable(defaultFeatureType);
2029

    
2030
        } catch (Exception e) {
2031
            throw new GetFeatureTypeException(e, getName());
2032
        }
2033
    }
2034

    
2035
    private FeatureType avoidEditable(FeatureType ft) {
2036
        if (ft instanceof EditableFeatureType) {
2037
            return ((EditableFeatureType) ft).getNotEditableCopy();
2038
        } else {
2039
            return ft;
2040
        }
2041
    }
2042

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

    
2074
    public FeatureType getProviderDefaultFeatureType() {
2075
        return defaultFeatureType;
2076
    }
2077

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

    
2112
    public List getProviderFeatureTypes() throws DataException {
2113
        return Collections.unmodifiableList(this.featureTypes);
2114
    }
2115

    
2116
    @Override
2117
    public Feature createFeature(FeatureProvider data) throws DataException {
2118
        DefaultFeature feature = new DefaultFeature(this, data);
2119
        return feature;
2120
    }
2121

    
2122
    public Feature createFeature(FeatureProvider data, FeatureType type)
2123
        throws DataException {
2124
        // FIXME: falta por implementar
2125
        // Comprobar si es un subtipo del feature de data
2126
        // y construir un feature usando el subtipo.
2127
        // Probablemente requiera generar una copia del data.
2128
        throw new NotYetImplemented();
2129
    }
2130

    
2131
    @Override
2132
    public EditableFeature createNewFeature(FeatureType type,
2133
        Feature defaultValues) throws DataException {
2134
        try {
2135
            FeatureProvider data = createNewFeatureProvider(type);
2136
            DefaultEditableFeature feature =
2137
                new DefaultEditableFeature(this, data);
2138
            feature.initializeValues(defaultValues);
2139
            data.setNew(true);
2140

    
2141
            return feature;
2142
        } catch (Exception e) {
2143
            throw new CreateFeatureException(e, getName());
2144
        }
2145
    }
2146

    
2147
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2148
        throws DataException {
2149
        type = this.fixFeatureType((DefaultFeatureType) type);
2150
        FeatureProvider data = this.provider.createFeatureProvider(type);
2151
        data.setNew(true);
2152
        if (type.hasOID() && (data.getOID() == null)) {
2153
            data.setOID(this.provider.createNewOID());
2154
        } else {
2155
            data.setOID(this.getTemporalOID());
2156
        }
2157
        return data;
2158

    
2159
    }
2160

    
2161
    @Override
2162
    public EditableFeature createNewFeature(FeatureType type,
2163
        boolean defaultValues) throws DataException {
2164
        try {
2165
            FeatureProvider data = createNewFeatureProvider(type);
2166
            DefaultEditableFeature feature =
2167
                new DefaultEditableFeature(this, data);
2168
            if (defaultValues) {
2169
                feature.initializeValues();
2170
            }
2171
            return feature;
2172
        } catch (Exception e) {
2173
            throw new CreateFeatureException(e, getName());
2174
        }
2175
    }
2176

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

    
2184
    @Override
2185
    public EditableFeature createNewFeature() throws DataException {
2186
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2187
    }
2188

    
2189
    @Override
2190
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2191
        FeatureType ft = this.getDefaultFeatureType();
2192
        EditableFeature f = this.createNewFeature(ft, false);
2193
                for( FeatureAttributeDescriptor desc : ft ) {
2194
                        try {
2195
                                f.set(desc.getName(), defaultValues.get(desc.getName()));
2196
                        } catch(Throwable th) {
2197
                                // Ignore
2198
                        }
2199
                }
2200
        return f;
2201
    }
2202

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

    
2209
    @Override
2210
    public EditableFeatureType createFeatureType(String id) {
2211
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2212
        return ftype;
2213
    }
2214

    
2215
    //
2216
    // ====================================================================
2217
    // Index related methods
2218
    //
2219

    
2220
    @Override
2221
    public FeatureIndexes getIndexes() {
2222
        return this.indexes;
2223
    }
2224

    
2225
    @Override
2226
    public FeatureIndex createIndex(FeatureType featureType,
2227
        String attributeName, String indexName) throws DataException {
2228
        return createIndex(null, featureType, attributeName, indexName);
2229
    }
2230

    
2231
    @Override
2232
    public FeatureIndex createIndex(String indexTypeName,
2233
        FeatureType featureType, String attributeName, String indexName)
2234
        throws DataException {
2235

    
2236
        return createIndex(indexTypeName, featureType, attributeName,
2237
            indexName, false, null);
2238
    }
2239

    
2240
    @Override
2241
    public FeatureIndex createIndex(FeatureType featureType,
2242
        String attributeName, String indexName, Observer observer)
2243
        throws DataException {
2244
        return createIndex(null, featureType, attributeName, indexName,
2245
            observer);
2246
    }
2247

    
2248
    @Override
2249
    public FeatureIndex createIndex(String indexTypeName,
2250
        FeatureType featureType, String attributeName, String indexName,
2251
        final Observer observer) throws DataException {
2252

    
2253
        return createIndex(indexTypeName, featureType, attributeName,
2254
            indexName, true, observer);
2255
    }
2256

    
2257
    private FeatureIndex createIndex(String indexTypeName,
2258
        FeatureType featureType, String attributeName, String indexName,
2259
        boolean background, final Observer observer) throws DataException {
2260

    
2261
        checkNotInAppendMode();
2262
        FeatureIndexProviderServices index;
2263
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2264
                featureType, indexName,
2265
                featureType.getAttributeDescriptor(attributeName));
2266

    
2267
        try {
2268
            index.fill(background, observer);
2269
        } catch (FeatureIndexException e) {
2270
            throw new InitializeException(index.getName(), e);
2271
        }
2272

    
2273
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2274
        return index;
2275
    }
2276

    
2277
    //
2278
    // ====================================================================
2279
    // Transforms related methods
2280
    //
2281

    
2282
    @Override
2283
    public FeatureStoreTransforms getTransforms() {
2284
        return this.transforms;
2285
    }
2286

    
2287
    @Override
2288
    public FeatureQuery createFeatureQuery() {
2289
        return new DefaultFeatureQuery();
2290
    }
2291

    
2292
    @Override
2293
    public DataQuery createQuery() {
2294
        return createFeatureQuery();
2295
    }
2296

    
2297
    //
2298
    // ====================================================================
2299
    // UndoRedo related methods
2300
    //
2301

    
2302
    @Override
2303
    public boolean canRedo() {
2304
        return commands.canRedo();
2305
    }
2306

    
2307
    @Override
2308
    public boolean canUndo() {
2309
        return commands.canUndo();
2310
    }
2311

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

    
2319
    @Override
2320
    public void undo(int num) throws UndoException {
2321
        for (int i = 0; i < num; i++) {
2322
            undo();
2323
        }
2324
    }
2325

    
2326
    //
2327
    // ====================================================================
2328
    // Metadata related methods
2329
    //
2330

    
2331
    @Override
2332
    public Object getMetadataID() {
2333
        return this.provider.getSourceId();
2334
    }
2335

    
2336
    @Override
2337
    public void delegate(DynObject dynObject) {
2338
        this.metadata.delegate(dynObject);
2339
    }
2340

    
2341
    @Override
2342
    public DynClass getDynClass() {
2343
        return this.metadata.getDynClass();
2344
    }
2345

    
2346
    @Override
2347
        public Object getDynValue(String name) throws DynFieldNotFoundException {
2348
                if( this.transforms.hasDynValue(name) ) {
2349
                        return this.transforms.getDynValue(name);
2350
                }
2351
                if (this.metadata.hasDynValue(name)) {
2352
                        return this.metadata.getDynValue(name);
2353
                }
2354
                if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2355
                        return this.provider.getProviderName();
2356
                } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2357
                        return this.provider.getSourceId();
2358
                } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2359
                        try {
2360
                                return this.getDefaultFeatureType();
2361
                        } catch (DataException e) {
2362
                                return null;
2363
                        }
2364
                }
2365
                return this.metadata.getDynValue(name);
2366
        }
2367

    
2368
    @Override
2369
    public boolean hasDynValue(String name) {
2370
                if( this.transforms.hasDynValue(name) ) {
2371
                        return true;
2372
                }
2373
        return this.metadata.hasDynValue(name);
2374
    }
2375

    
2376
    @Override
2377
    public boolean hasDynMethod(String name) {
2378
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2379
    }
2380

    
2381
    @Override
2382
    public void implement(DynClass dynClass) {
2383
        this.metadata.implement(dynClass);
2384
    }
2385

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

    
2392
    @Override
2393
    public Object invokeDynMethod(int code, Object[] args)
2394
        throws DynMethodException {
2395
        return this.metadata.invokeDynMethod(this, code, args);
2396
    }
2397

    
2398
    @Override
2399
    public void setDynValue(String name, Object value)
2400
        throws DynFieldNotFoundException {
2401
                if( this.transforms.hasDynValue(name) ) {
2402
                        this.transforms.setDynValue(name, value);
2403
                        return;
2404
                }
2405
        this.metadata.setDynValue(name, value);
2406

    
2407
    }
2408

    
2409
    /*
2410
     * (non-Javadoc)
2411
     *
2412
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2413
     */
2414
    @Override
2415
    public Set getMetadataChildren() {
2416
        return this.metadataChildren;
2417
    }
2418

    
2419
    /*
2420
     * (non-Javadoc)
2421
     *
2422
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2423
     */
2424
    @Override
2425
    public String getMetadataName() {
2426
        return this.provider.getProviderName();
2427
    }
2428

    
2429
    public FeatureTypeManager getFeatureTypeManager() {
2430
        return this.featureTypeManager;
2431
    }
2432

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

    
2454
    private Long getTemporalOID() {
2455
        return this.temporalOid++;
2456
    }
2457

    
2458
    @Override
2459
    public FeatureType getProviderFeatureType(String featureTypeId) {
2460
        if (featureTypeId == null) {
2461
            return this.defaultFeatureType;
2462
        }
2463
        FeatureType type;
2464
        Iterator iter = this.featureTypes.iterator();
2465
        while (iter.hasNext()) {
2466
            type = (FeatureType) iter.next();
2467
            if (type.getId().equals(featureTypeId)) {
2468
                return type;
2469
            }
2470
        }
2471
        return null;
2472
    }
2473

    
2474
    @Override
2475
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2476
        return ((DefaultFeature) feature).getData();
2477
    }
2478

    
2479
    @Override
2480
    public DataStore getStore() {
2481
        return this;
2482
    }
2483

    
2484
    @Override
2485
    public FeatureStore getFeatureStore() {
2486
        return this;
2487
    }
2488

    
2489
    @Override
2490
    public void createCache(String name, DynObject parameters)
2491
        throws DataException {
2492
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2493
        if (cache == null) {
2494
            throw new CreateException("FeaureCacheProvider", null);
2495
        }
2496
        cache.apply(this, provider);
2497
        provider = cache;
2498

    
2499
        featureCount = null;
2500
    }
2501

    
2502
    @Override
2503
    public FeatureCache getCache() {
2504
        return cache;
2505
    }
2506

    
2507
    @Override
2508
    public void clear() {
2509
        if (metadata != null) {
2510
            metadata.clear();
2511
        }
2512
    }
2513

    
2514
    @Override
2515
    public String getName() {
2516
        if( this.provider != null ) {
2517
            return this.provider.getName();
2518
        }
2519
        if( this.parameters instanceof HasAFile ) {
2520
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
2521
        }
2522
        return "unknow";
2523
    }
2524

    
2525
    @Override
2526
    public String getFullName() {
2527
        try {
2528
            if( this.provider!=null ) {
2529
                return this.provider.getFullName();
2530
            }
2531
            if( this.parameters instanceof HasAFile ) {
2532
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
2533
            }
2534
            return null;
2535
        } catch(Throwable th) {
2536
            return null;
2537
        }
2538
    }
2539

    
2540
    @Override
2541
    public String getProviderName() {
2542
        if( this.provider!=null ) {
2543
            return this.provider.getProviderName();
2544
        }
2545
        if( this.parameters != null ) {
2546
            return this.parameters.getDataStoreName();
2547
        }
2548
        return null;
2549

    
2550
    }
2551

    
2552
    @Override
2553
    public boolean isKnownEnvelope() {
2554
        return this.provider.isKnownEnvelope();
2555
    }
2556

    
2557
    @Override
2558
    public boolean hasRetrievedFeaturesLimit() {
2559
        return this.provider.hasRetrievedFeaturesLimit();
2560
    }
2561

    
2562
    @Override
2563
    public int getRetrievedFeaturesLimit() {
2564
        return this.provider.getRetrievedFeaturesLimit();
2565
    }
2566

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

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

    
2583
    @Override
2584
    public Collection getTimes(Interval interval) {
2585
        if( this.timeSupport!=null ) {
2586
            return this.timeSupport.getTimes(interval);
2587
        }
2588
        return this.provider.getTimes(interval);
2589
    }
2590

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

    
2620
        this.timeSupport = timeSupport;
2621
    }
2622

    
2623
    @Override
2624
    @SuppressWarnings("CloneDoesntCallSuperClone")
2625
    public Object clone() throws CloneNotSupportedException {
2626

    
2627
        DataStoreParameters dsp = getParameters();
2628

    
2629
        DefaultFeatureStore cloned_store = null;
2630

    
2631
        try {
2632
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2633
                openStore(this.getProviderName(), dsp);
2634
            if (transforms != null) {
2635
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2636
                cloned_store.transforms.setStoreForClone(cloned_store);
2637
            }
2638
        } catch (Exception e) {
2639
            throw new CloneException(e);
2640
        }
2641
        return cloned_store;
2642

    
2643
    }
2644

    
2645
    @Override
2646
    public Feature getFeature(DynObject dynobject) {
2647
        if (dynobject instanceof DynObjectFeatureFacade){
2648
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2649
            return f;
2650
        }
2651
        return null;
2652
    }
2653

    
2654
    @Override
2655
    public Iterator iterator() {
2656
        try {
2657
            return this.getFeatureSet().fastIterator();
2658
        } catch (DataException ex) {
2659
            throw new RuntimeException(ex);
2660
        }
2661
    }
2662

    
2663
    @Override
2664
    public ExpressionBuilder createExpressionBuilder() {
2665
        if( this.provider instanceof FeatureStoreProvider_v2 ) {
2666
            return ((FeatureStoreProvider_v2)this.provider).createExpression();
2667
        }
2668
        return new SQLBuilderBase();
2669
    }
2670

    
2671
    @Override
2672
    public ExpressionBuilder createExpression() {
2673
        return createExpressionBuilder();
2674
    }
2675

    
2676
    public FeatureSet features() throws DataException {
2677
        // This is to avoid jython to create a property with this name
2678
        // to access method getFeatures.
2679
        return this.getFeatureSet();
2680
    }
2681

    
2682
    @Override
2683
    public DataStoreProviderFactory getProviderFactory() {
2684
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
2685
        return factory;
2686
    }
2687

    
2688
    @Override
2689
    public void useCache(String providerName, DynObject parameters) throws DataException {
2690
        throw new UnsupportedOperationException();
2691
    }
2692

    
2693
    @Override
2694
    public boolean isBroken() {
2695
        return this.state.isBroken();
2696
    }
2697

    
2698
    @Override
2699
    public Throwable getBreakingsCause() {
2700
            return this.state.getBreakingsCause();
2701
    }
2702

    
2703
    @Override
2704
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
2705
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
2706
      if( !factory.supportNumericOID() ) {
2707
          return null;
2708
      }
2709
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
2710
      return wrappedIndex;
2711
  }
2712

    
2713
    @Override
2714
    public FeatureReference getFeatureReference(String code) {
2715
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
2716
        return featureReference;
2717
    }
2718
}