Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.impl / src / main / java / org / gvsig / fmap / dal / feature / impl / DefaultFeatureStore.java @ 43958

History | View | Annotate | Download (91.2 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 java.io.File;
28
import org.gvsig.fmap.dal.feature.impl.editing.memory.SpatialManager;
29
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureTypeManager;
30
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureManager;
31
import org.gvsig.fmap.dal.feature.spi.SQLBuilderBase;
32

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

    
45
import org.apache.commons.io.FilenameUtils;
46
import org.apache.commons.lang3.StringUtils;
47
import org.cresques.cts.IProjection;
48

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

    
168
import org.slf4j.Logger;
169
import org.slf4j.LoggerFactory;
170

    
171
public class DefaultFeatureStore extends AbstractDisposable implements
172
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
173

    
174
    private static final Logger LOG = LoggerFactory
175
        .getLogger(DefaultFeatureStore.class);
176

    
177
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
178

    
179
    private DataStoreParameters parameters = null;
180
    private FeatureSelection selection;
181
    private FeatureLocks locks;
182

    
183
    private DelegateWeakReferencingObservable delegateObservable =
184
        new DelegateWeakReferencingObservable(this);
185

    
186
    private FeatureCommandsStack commands;
187
    
188
    /*
189
    TODO: Sustituir estos tres manager por un EditingManager
190
    */
191
    private FeatureTypeManager featureTypeManager;
192
    private FeatureManager featureManager;
193
    private SpatialManager spatialManager;
194

    
195
    private FeatureType defaultFeatureType = null;
196
    private List featureTypes = new ArrayList();
197

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

    
203
    private DefaultDataManager dataManager = null;
204

    
205
    private FeatureStoreProvider provider = null;
206

    
207
    private DefaultFeatureIndexes indexes;
208

    
209
    private DefaultFeatureStoreTransforms transforms;
210

    
211
    DelegatedDynObject metadata;
212

    
213
    private Set metadataChildren;
214

    
215
    private Long featureCount = null;
216

    
217
    private long temporalOid = 0;
218

    
219
    private FeatureCacheProvider cache;
220

    
221
    StateInformation state;
222

    
223
    FeatureStoreTimeSupport timeSupport;
224

    
225

    
226
    private class StateInformation extends HashMap<Object, Object> {
227

    
228
        private static final long serialVersionUID = 4109026189635185666L;
229

    
230
        private boolean broken;
231
        private Throwable breakingsCause;
232

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

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

    
245
        public boolean isBroken() {
246
            return this.broken;
247
        }
248

    
249
        public void broken() {
250
            this.broken = true;
251
        }
252

    
253
        public Throwable getBreakingsCause() {
254
            return this.breakingsCause;
255
        }
256

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

    
265

    
266

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

    
276
    public DefaultFeatureStore() {
277
        this.state = new StateInformation();
278
    }
279

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

    
284
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
285

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

    
291
        this.dataManager = (DefaultDataManager) dataManager;
292

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

    
301
    }
302

    
303
    @Override
304
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
305
        this.provider = (FeatureStoreProvider) provider;
306
        this.delegate((DynObject) provider);
307
        this.metadataChildren = new HashSet();
308
        this.metadataChildren.add(provider);
309
        loadDALFile();
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
                saveDALFile();
1473
                exitEditingMode();
1474
                updateIndexes();
1475
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1476
                break;
1477
            }
1478
        } catch (PerformEditingException pee) {
1479
            throw new WriteException(provider.getSourceId().toString(), pee);
1480
        } catch (Exception e) {
1481
            throw new FinishEditingException(e);
1482
        }
1483
    }
1484

    
1485
    @SuppressWarnings("UseSpecificCatch")
1486
    private void saveDALFile() {       
1487
        try {
1488
            DataServerExplorer explorer = this.getExplorer();
1489
            if( explorer == null ) {
1490
                return;
1491
            }
1492
            File f = explorer.getResourcePath(this, "dal");
1493
            if( f == null ) {
1494
                return;
1495
            }
1496
            DALFile dalFile = DALFile.getDALFile();
1497
            dalFile.setStore(this);
1498
            if( !dalFile.isEmpty() ) {
1499
                dalFile.write(f);
1500
            }
1501
        } catch (Exception ex) {
1502
            LOG.warn("Can't save DAL File", ex);
1503
        }
1504
    }
1505
    
1506
    @SuppressWarnings("UseSpecificCatch")
1507
    private void loadDALFile() {
1508
        try {
1509
            DataServerExplorer explorer = this.getExplorer();
1510
            if( explorer == null ) {
1511
                return;
1512
            }
1513
            File f = explorer.getResourcePath(this, "dal");
1514
            if( f == null || !f.exists() ) {
1515
                return;
1516
            }
1517
            DALFile dalFile = DALFile.getDALFile(f);
1518
            if( !dalFile.isEmpty() ) {
1519
                dalFile.updateStore(this);
1520
            }
1521
        } catch (Exception ex) {
1522
            LOG.warn("Can't load DAL File", ex);
1523
        }
1524
    }
1525
    
1526
    /**
1527
     * Save changes in the provider without leaving the edit mode.
1528
     * Do not call observers to communicate a change of ediding mode.
1529
     * The operation's history is eliminated to prevent inconsistencies
1530
     * in the data.
1531
     *
1532
     * @throws DataException
1533
     */
1534
    @Override
1535
    synchronized public void commitChanges() throws DataException {
1536
      LOG.debug("commitChanges of mode: {}", mode);
1537
      if( !canCommitChanges() ) {
1538
              throw new WriteNotAllowedException(getName());
1539
      }
1540
      try {
1541
        switch (mode) {
1542
        case MODE_QUERY:
1543
          throw new NeedEditingModeException(this.getName());
1544

    
1545
        case MODE_APPEND:
1546
          this.provider.endAppend();
1547
          exitEditingMode();
1548
          invalidateIndexes();
1549
          this.provider.beginAppend();
1550
          hasInserts = false;
1551
          break;
1552

    
1553
        case MODE_FULLEDIT:
1554
          if (hasStrongChanges && !this.allowWrite()) {
1555
            throw new WriteNotAllowedException(getName());
1556
          }
1557
          if (hasStrongChanges) {
1558
            validateFeatures(Feature.FINISH_EDITING);
1559
            provider.performChanges(featureManager.getDeleted(),
1560
              featureManager.getInserted(),
1561
              featureManager.getUpdated(),
1562
              featureTypeManager.getFeatureTypesChanged());
1563
          }
1564
          invalidateIndexes();
1565
          featureManager = new FeatureManager();
1566
          featureTypeManager = new FeatureTypeManager(this);
1567
          spatialManager = new SpatialManager(this, provider.getEnvelope());
1568

    
1569
          commands =
1570
            new DefaultFeatureCommandsStack(this, featureManager,
1571
              spatialManager, featureTypeManager);
1572
          featureCount = null;
1573
          hasStrongChanges = false;
1574
          hasInserts = false;
1575
          break;
1576
        }
1577
      } catch (Exception e) {
1578
        throw new FinishEditingException(e);
1579
      }
1580
    }
1581

    
1582
    @Override
1583
    synchronized public boolean canCommitChanges() throws DataException {
1584
        if ( !this.allowWrite()) {
1585
                return false;
1586
        }
1587
            switch (mode) {
1588
            default:
1589
        case MODE_QUERY:
1590
                return false;
1591

    
1592
        case MODE_APPEND:
1593
                return true;
1594

    
1595
        case MODE_FULLEDIT:
1596
            List types = this.getFeatureTypes();
1597
            for( int i=0; i<types.size(); i++ ) {
1598
                    Object type = types.get(i);
1599
                    if( type instanceof DefaultEditableFeatureType ) {
1600
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1601
                                    return false;
1602
                            }
1603
                    }
1604
            }
1605
            return true;
1606
            }
1607
    }
1608

    
1609
    @Override
1610
    public void beginEditingGroup(String description)
1611
        throws NeedEditingModeException {
1612
        checkInEditingMode();
1613
        commands.startComplex(description);
1614
    }
1615

    
1616
    @Override
1617
    public void endEditingGroup() throws NeedEditingModeException {
1618
        checkInEditingMode();
1619
        commands.endComplex();
1620
    }
1621

    
1622
    @Override
1623
    public boolean isAppendModeSupported() {
1624
        return this.provider.supportsAppendMode();
1625
    }
1626

    
1627
    @Override
1628
    public void export(DataServerExplorer explorer, String provider,
1629
        NewFeatureStoreParameters params) throws DataException {
1630

    
1631
        if (this.getFeatureTypes().size() != 1) {
1632
            throw new NotYetImplemented(
1633
                "export whith more than one type not yet implemented");
1634
        }
1635
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1636
        FeatureStore target = null;
1637
        FeatureSet features = null;
1638
        DisposableIterator iterator = null;
1639
        try {
1640
            FeatureType type = this.getDefaultFeatureType();
1641
            if ((params.getDefaultFeatureType() == null)
1642
                || (params.getDefaultFeatureType().size() == 0)) {
1643
                params.setDefaultFeatureType(type.getEditable());
1644

    
1645
            }
1646
            explorer.add(provider, params, true);
1647

    
1648
            DataManager manager = DALLocator.getDataManager();
1649
            target = (FeatureStore) manager.openStore(provider, params);
1650
            FeatureType targetType = target.getDefaultFeatureType();
1651

    
1652
            target.edit(MODE_APPEND);
1653
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
1654
            if (featureSelection.getSize() > 0) {
1655
                features = this.getFeatureSelection();
1656
            } else {
1657
                if ((pkattrs != null) && (pkattrs.length > 0)) {
1658
                    FeatureQuery query = createFeatureQuery();
1659
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
1660
                        query.getOrder().add(pkattr.getName(), true);
1661
                    }
1662
                    features = this.getFeatureSet(query);
1663
                } else {
1664
                    features = this.getFeatureSet();
1665
                }
1666
            }
1667
            iterator = features.fastIterator();
1668
            while (iterator.hasNext()) {
1669
                DefaultFeature feature = (DefaultFeature) iterator.next();
1670
                target.insert(target.createNewFeature(targetType, feature));
1671
            }
1672
            target.finishEditing();
1673
            target.dispose();
1674
        } catch (Exception e) {
1675
            throw new DataExportException(e, params.toString());
1676
        } finally {
1677
            dispose(iterator);
1678
            dispose(features);
1679
            dispose(target);
1680
        }
1681
    }
1682

    
1683
    //
1684
    // ====================================================================
1685
    // Obtencion de datos
1686
    // getDataCollection, getFeatureCollection
1687
    //
1688

    
1689
    @Override
1690
    public DataSet getDataSet() throws DataException {
1691
        checkNotInAppendMode();
1692
        FeatureQuery query =
1693
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1694
        return new DefaultFeatureSet(this, query);
1695
    }
1696

    
1697
    @Override
1698
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1699
        checkNotInAppendMode();
1700
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1701
    }
1702

    
1703
    @Override
1704
    public void getDataSet(Observer observer) throws DataException {
1705
        checkNotInAppendMode();
1706
        this.getFeatureSet(null, observer);
1707
    }
1708

    
1709
    @Override
1710
    public void getDataSet(DataQuery dataQuery, Observer observer)
1711
        throws DataException {
1712
        checkNotInAppendMode();
1713
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1714
    }
1715

    
1716
    @Override
1717
    public FeatureSet getFeatureSet() throws DataException {
1718
        return this.getFeatureSet((FeatureQuery)null);
1719
    }
1720

    
1721
    @Override
1722
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1723
        throws DataException {
1724
        checkNotInAppendMode();
1725
        if( featureQuery==null ) {
1726
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1727
        }
1728
        return new DefaultFeatureSet(this, featureQuery);
1729
    }
1730

    
1731
    @Override
1732
    public FeatureSet getFeatureSet(String filter) throws DataException {
1733
        return this.getFeatureSet(filter, null, true);
1734
    }
1735

    
1736
    @Override
1737
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
1738
        return this.getFeatureSet(filter, sortBy, true);
1739
    }
1740

    
1741
    @Override
1742
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
1743
        FeatureQuery query = this.createFeatureQuery();
1744
        if( !StringUtils.isEmpty(filter) ) {
1745
            query.setFilter(filter);
1746
        }
1747
        if( !StringUtils.isEmpty(sortBy) ) {
1748
            query.getOrder().add(sortBy, asc);
1749
        }
1750
        return this.getFeatureSet(query);
1751
    }
1752
    
1753
    @Override
1754
    public List<Feature> getFeatures(String filter)  {
1755
        return this.getFeatures(filter, null, true);
1756
    }
1757

    
1758
    @Override
1759
    public List<Feature> getFeatures(String filter, String sortBy)  {
1760
        return this.getFeatures(filter, sortBy, true);
1761
    }
1762

    
1763
    @Override
1764
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
1765
        FeatureQuery query = this.createFeatureQuery();
1766
        if( !StringUtils.isEmpty(filter) ) {
1767
            query.setFilter(filter);
1768
        }
1769
        if( !StringUtils.isEmpty(sortBy) ) {
1770
            query.getOrder().add(sortBy, asc);
1771
        }
1772
        return this.getFeatures(query, 100);
1773
    }
1774
    
1775
    @Override
1776
    public List<Feature> getFeatures(FeatureQuery query)  {
1777
        return this.getFeatures(query, 100);
1778
    }
1779
    
1780
    @Override
1781
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
1782
        try {
1783
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
1784
            return pager.asList();
1785
        } catch (BaseException ex) {
1786
            throw new RuntimeException("Can't create the list of features.", ex);
1787
        }
1788
    }
1789

    
1790
    @Override
1791
    public List<Feature> getFeatures() {
1792
        return this.getFeatures(null, 500);
1793
    }
1794

    
1795
    @Override
1796
    public Feature findFirst(String filter) throws DataException {
1797
        return this.findFirst(filter, null, true);
1798
    }
1799

    
1800
    @Override
1801
    public Feature findFirst(String filter, String sortBy) throws DataException {
1802
        return this.findFirst(filter, sortBy, true);
1803
    }
1804

    
1805
    @Override
1806
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
1807
        FeatureSet set = this.getFeatureSet(filter, sortBy, asc);
1808
        if( set==null || set.isEmpty() ) {
1809
            return null;
1810
        }
1811
        DisposableIterator it = set.iterator();
1812
        Feature f = (Feature) it.next();
1813
        it.dispose();
1814
        return f;
1815
    }
1816
    
1817
    @Override
1818
    public void accept(Visitor visitor) throws BaseException {
1819
        FeatureSet set = getFeatureSet();
1820
        try {
1821
            set.accept(visitor);
1822
        } finally {
1823
            set.dispose();
1824
        }
1825
    }
1826

    
1827
    @Override
1828
    public void accept(Visitor visitor, DataQuery dataQuery)
1829
        throws BaseException {
1830
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
1831
        try {
1832
            set.accept(visitor);
1833
        } finally {
1834
            set.dispose();
1835
        }
1836
    }
1837

    
1838
    public FeatureType getFeatureType(FeatureQuery featureQuery)
1839
        throws DataException {
1840
        DefaultFeatureType fType =
1841
            (DefaultFeatureType) this.getFeatureType(featureQuery
1842
                .getFeatureTypeId());
1843
        if( featureQuery.hasAttributeNames() || featureQuery.hasConstantsAttributeNames() ) {
1844
            return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames() );
1845
        }
1846
        return fType;
1847
    }
1848

    
1849
    @Override
1850
    public void getFeatureSet(Observer observer) throws DataException {
1851
        checkNotInAppendMode();
1852
        this.getFeatureSet(null, observer);
1853
    }
1854

    
1855
    @Override
1856
    public void getFeatureSet(FeatureQuery query, Observer observer)
1857
        throws DataException {
1858
        class LoadInBackGround implements Runnable {
1859

    
1860
            private final FeatureStore store;
1861
            private final FeatureQuery query;
1862
            private final Observer observer;
1863

    
1864
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
1865
                Observer observer) {
1866
                this.store = store;
1867
                this.query = query;
1868
                this.observer = observer;
1869
            }
1870

    
1871
            void notify(FeatureStoreNotification theNotification) {
1872
                observer.update(store, theNotification);
1873
            }
1874

    
1875
            @Override
1876
            public void run() {
1877
                FeatureSet set = null;
1878
                try {
1879
                    set = store.getFeatureSet(query);
1880
                    notify(new DefaultFeatureStoreNotification(store,
1881
                        FeatureStoreNotification.LOAD_FINISHED, set));
1882
                } catch (Exception e) {
1883
                    notify(new DefaultFeatureStoreNotification(store,
1884
                        FeatureStoreNotification.LOAD_FINISHED, e));
1885
                } finally {
1886
                    dispose(set);
1887
                }
1888
            }
1889
        }
1890

    
1891
        checkNotInAppendMode();
1892
        if (query == null) {
1893
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
1894
        }
1895
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
1896
        Thread thread = new Thread(task, "Load Feature Set in background");
1897
        thread.start();
1898
    }
1899

    
1900
    @Override
1901
    public Feature getFeatureByReference(FeatureReference reference)
1902
        throws DataException {
1903
        checkNotInAppendMode();
1904
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
1905
        FeatureType featureType;
1906
        if (ref.getFeatureTypeId() == null) {
1907
            featureType = this.getDefaultFeatureType();
1908
        } else {
1909
            featureType = this.getFeatureType(ref.getFeatureTypeId());
1910
        }
1911
        return this.getFeatureByReference(reference, featureType);
1912
    }
1913

    
1914
    @Override
1915
    public Feature getFeatureByReference(FeatureReference reference,
1916
        FeatureType featureType) throws DataException {
1917
        checkNotInAppendMode();
1918
        featureType = fixFeatureType((DefaultFeatureType) featureType);
1919
        if (this.mode == MODE_FULLEDIT) {
1920
            Feature f = featureManager.get(reference, this, featureType);
1921
            if (f != null) {
1922
                return f;
1923
            }
1924
        }
1925

    
1926
        FeatureType sourceFeatureType = featureType;
1927
        if (!this.transforms.isEmpty()) {
1928
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
1929
        }
1930
        // TODO comprobar que el id es de este store
1931

    
1932
        DefaultFeature feature =
1933
            new DefaultFeature(this,
1934
                this.provider.getFeatureProviderByReference(
1935
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
1936

    
1937
        if (!this.transforms.isEmpty()) {
1938
            return this.transforms.applyTransform(feature, featureType);
1939
        }
1940
        return feature;
1941
    }
1942

    
1943
    //
1944
    // ====================================================================
1945
    // Gestion de features
1946
    //
1947

    
1948
    private FeatureType fixFeatureType(DefaultFeatureType type)
1949
        throws DataException {
1950
        FeatureType original = this.getDefaultFeatureType();
1951

    
1952
        if ((type == null) || type.equals(original)) {
1953
            return original;
1954
        } else {
1955
            if (!type.isSubtypeOf(original)) {
1956
                Iterator iter = this.getFeatureTypes().iterator();
1957
                FeatureType tmpType;
1958
                boolean found = false;
1959
                while (iter.hasNext()) {
1960
                    tmpType = (FeatureType) iter.next();
1961
                    if (type.equals(tmpType)) {
1962
                        return type;
1963

    
1964
                    } else
1965
                        if (type.isSubtypeOf(tmpType)) {
1966
                            found = true;
1967
                            original = tmpType;
1968
                            break;
1969
                        }
1970

    
1971
                }
1972
                if (!found) {
1973
                    throw new IllegalFeatureTypeException(getName());
1974
                }
1975
            }
1976
        }
1977

    
1978
        // Checks that type has all fields of pk
1979
        // else add the missing attributes at the end.
1980
        if (!original.hasOID()) {
1981
            // Gets original pk attributes
1982
            DefaultEditableFeatureType edOriginal =
1983
                (DefaultEditableFeatureType) original.getEditable();
1984
            FeatureAttributeDescriptor orgAttr;
1985
            Iterator edOriginalIter = edOriginal.iterator();
1986
            while (edOriginalIter.hasNext()) {
1987
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1988
                if (!orgAttr.isPrimaryKey()) {
1989
                    edOriginalIter.remove();
1990
                }
1991
            }
1992

    
1993
            // Checks if all pk attributes are in type
1994
            Iterator typeIterator;
1995
            edOriginalIter = edOriginal.iterator();
1996
            FeatureAttributeDescriptor attr;
1997
            while (edOriginalIter.hasNext()) {
1998
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1999
                typeIterator = type.iterator();
2000
                while (typeIterator.hasNext()) {
2001
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2002
                    if (attr.getName().equals(orgAttr.getName())) {
2003
                        edOriginalIter.remove();
2004
                        break;
2005
                    }
2006
                }
2007
            }
2008

    
2009
            // add missing pk attributes if any
2010
            if (edOriginal.size() > 0) {
2011
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2012
                DefaultEditableFeatureType edType =
2013
                    (DefaultEditableFeatureType) original.getEditable();
2014
                edType.clear();
2015
                edType.addAll(type);
2016
                edType.addAll(edOriginal);
2017
                if (!isEditable) {
2018
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2019
                }
2020
            }
2021

    
2022
        }
2023

    
2024
        return type;
2025
    }
2026

    
2027
    @Override
2028
    public void validateFeatures(int mode) throws DataException {
2029
        FeatureSet collection = null;
2030
        DisposableIterator iter = null;
2031
        try {
2032
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2033
            if( rules==null || rules.isEmpty() ) {
2034
                return;
2035
            }
2036
            checkNotInAppendMode();
2037
            collection = this.getFeatureSet();
2038
            iter = collection.fastIterator();
2039
            long previousVersionOfUpdate = currentVersionOfUpdate();
2040
            while (iter.hasNext()) {
2041
                ((DefaultFeature) iter.next()).validate(mode);
2042
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2043
                    throw new ConcurrentDataModificationException(getName());
2044
                }
2045
            }
2046
        } catch (Exception e) {
2047
            throw new ValidateFeaturesException(e, getName());
2048
        } finally {
2049
            DisposeUtils.disposeQuietly(iter);
2050
            DisposeUtils.disposeQuietly(collection);
2051
        }
2052
    }
2053

    
2054
    @Override
2055
    public FeatureType getDefaultFeatureType() throws DataException {
2056
        try {
2057

    
2058
            if (isEditing()) {
2059
                FeatureType auxFeatureType =
2060
                    featureTypeManager.getType(defaultFeatureType.getId());
2061
                if (auxFeatureType != null) {
2062
                    return avoidEditable(auxFeatureType);
2063
                }
2064
            }
2065
            FeatureType type = this.transforms.getDefaultFeatureType();
2066
            if (type != null) {
2067
                return avoidEditable(type);
2068
            }
2069

    
2070
            return avoidEditable(defaultFeatureType);
2071

    
2072
        } catch (Exception e) {
2073
            throw new GetFeatureTypeException(e, getName());
2074
        }
2075
    }
2076

    
2077
    private FeatureType avoidEditable(FeatureType ft) {
2078
        if (ft instanceof EditableFeatureType) {
2079
            return ((EditableFeatureType) ft).getNotEditableCopy();
2080
        } else {
2081
            return ft;
2082
        }
2083
    }
2084

    
2085
    @Override
2086
    public FeatureType getFeatureType(String featureTypeId)
2087
        throws DataException {
2088
        if (featureTypeId == null) {
2089
            return this.getDefaultFeatureType();
2090
        }
2091
        try {
2092
            if (isEditing()) {
2093
                FeatureType auxFeatureType =
2094
                    featureTypeManager.getType(featureTypeId);
2095
                if (auxFeatureType != null) {
2096
                    return auxFeatureType;
2097
                }
2098
            }
2099
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2100
            if (type != null) {
2101
                return type;
2102
            }
2103
            Iterator iter = this.featureTypes.iterator();
2104
            while (iter.hasNext()) {
2105
                type = (FeatureType) iter.next();
2106
                if (type.getId().equals(featureTypeId)) {
2107
                    return type;
2108
                }
2109
            }
2110
            return null;
2111
        } catch (Exception e) {
2112
            throw new GetFeatureTypeException(e, getName());
2113
        }
2114
    }
2115

    
2116
    public FeatureType getProviderDefaultFeatureType() {
2117
        return defaultFeatureType;
2118
    }
2119

    
2120
    @Override
2121
    public List getFeatureTypes() throws DataException {
2122
        try {
2123
            List types;
2124
            if (isEditing()) {
2125
                types = new ArrayList();
2126
                Iterator it = featureTypes.iterator();
2127
                while (it.hasNext()) {
2128
                    FeatureType type = (FeatureType) it.next();
2129
                    FeatureType typeaux =
2130
                        featureTypeManager.getType(type.getId());
2131
                    if (typeaux != null) {
2132
                        types.add(typeaux);
2133
                    } else {
2134
                        types.add(type);
2135
                    }
2136
                }
2137
                it = featureTypeManager.newsIterator();
2138
                while (it.hasNext()) {
2139
                    FeatureType type = (FeatureType) it.next();
2140
                    types.add(type);
2141
                }
2142
            } else {
2143
                types = this.transforms.getFeatureTypes();
2144
                if (types == null) {
2145
                    types = featureTypes;
2146
                }
2147
            }
2148
            return Collections.unmodifiableList(types);
2149
        } catch (Exception e) {
2150
            throw new GetFeatureTypeException(e, getName());
2151
        }
2152
    }
2153

    
2154
    public List getProviderFeatureTypes() throws DataException {
2155
        return Collections.unmodifiableList(this.featureTypes);
2156
    }
2157

    
2158
    @Override
2159
    public Feature createFeature(FeatureProvider data) throws DataException {
2160
        DefaultFeature feature = new DefaultFeature(this, data);
2161
        return feature;
2162
    }
2163

    
2164
    public Feature createFeature(FeatureProvider data, FeatureType type)
2165
        throws DataException {
2166
        // FIXME: falta por implementar
2167
        // Comprobar si es un subtipo del feature de data
2168
        // y construir un feature usando el subtipo.
2169
        // Probablemente requiera generar una copia del data.
2170
        throw new NotYetImplemented();
2171
    }
2172

    
2173
    @Override
2174
    public EditableFeature createNewFeature(FeatureType type,
2175
        Feature defaultValues) throws DataException {
2176
        try {
2177
            FeatureProvider data = createNewFeatureProvider(type);
2178
            DefaultEditableFeature feature =
2179
                new DefaultEditableFeature(this, data);
2180
            feature.initializeValues(defaultValues);
2181
            data.setNew(true);
2182

    
2183
            return feature;
2184
        } catch (Exception e) {
2185
            throw new CreateFeatureException(e, getName());
2186
        }
2187
    }
2188

    
2189
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2190
        throws DataException {
2191
        type = this.fixFeatureType((DefaultFeatureType) type);
2192
        FeatureProvider data = this.provider.createFeatureProvider(type);
2193
        data.setNew(true);
2194
        if (type.hasOID() && (data.getOID() == null)) {
2195
            data.setOID(this.provider.createNewOID());
2196
        } else {
2197
            data.setOID(this.getTemporalOID());
2198
        }
2199
        return data;
2200

    
2201
    }
2202

    
2203
    @Override
2204
    public EditableFeature createNewFeature(FeatureType type,
2205
        boolean defaultValues) throws DataException {
2206
        try {
2207
            FeatureProvider data = createNewFeatureProvider(type);
2208
            DefaultEditableFeature feature =
2209
                new DefaultEditableFeature(this, data);
2210
            if (defaultValues) {
2211
                feature.initializeValues();
2212
            }
2213
            return feature;
2214
        } catch (Exception e) {
2215
            throw new CreateFeatureException(e, getName());
2216
        }
2217
    }
2218

    
2219
    @Override
2220
    public EditableFeature createNewFeature(boolean defaultValues)
2221
        throws DataException {
2222
        return this.createNewFeature(this.getDefaultFeatureType(),
2223
            defaultValues);
2224
    }
2225

    
2226
    @Override
2227
    public EditableFeature createNewFeature() throws DataException {
2228
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2229
    }
2230

    
2231
    @Override
2232
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2233
        FeatureType ft = this.getDefaultFeatureType();
2234
        EditableFeature f = this.createNewFeature(ft, false);
2235
                for( FeatureAttributeDescriptor desc : ft ) {
2236
                        try {
2237
                                f.set(desc.getName(), defaultValues.get(desc.getName()));
2238
                        } catch(Throwable th) {
2239
                                // Ignore
2240
                        }
2241
                }
2242
        return f;
2243
    }
2244

    
2245
    @Override
2246
    public EditableFeatureType createFeatureType() {
2247
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2248
        return ftype;
2249
    }
2250

    
2251
    @Override
2252
    public EditableFeatureType createFeatureType(String id) {
2253
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2254
        return ftype;
2255
    }
2256

    
2257
    //
2258
    // ====================================================================
2259
    // Index related methods
2260
    //
2261

    
2262
    @Override
2263
    public FeatureIndexes getIndexes() {
2264
        return this.indexes;
2265
    }
2266

    
2267
    @Override
2268
    public FeatureIndex createIndex(FeatureType featureType,
2269
        String attributeName, String indexName) throws DataException {
2270
        return createIndex(null, featureType, attributeName, indexName);
2271
    }
2272

    
2273
    @Override
2274
    public FeatureIndex createIndex(String indexTypeName,
2275
        FeatureType featureType, String attributeName, String indexName)
2276
        throws DataException {
2277

    
2278
        return createIndex(indexTypeName, featureType, attributeName,
2279
            indexName, false, null);
2280
    }
2281

    
2282
    @Override
2283
    public FeatureIndex createIndex(FeatureType featureType,
2284
        String attributeName, String indexName, Observer observer)
2285
        throws DataException {
2286
        return createIndex(null, featureType, attributeName, indexName,
2287
            observer);
2288
    }
2289

    
2290
    @Override
2291
    public FeatureIndex createIndex(String indexTypeName,
2292
        FeatureType featureType, String attributeName, String indexName,
2293
        final Observer observer) throws DataException {
2294

    
2295
        return createIndex(indexTypeName, featureType, attributeName,
2296
            indexName, true, observer);
2297
    }
2298

    
2299
    private FeatureIndex createIndex(String indexTypeName,
2300
        FeatureType featureType, String attributeName, String indexName,
2301
        boolean background, final Observer observer) throws DataException {
2302

    
2303
        checkNotInAppendMode();
2304
        FeatureIndexProviderServices index;
2305
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2306
                featureType, indexName,
2307
                featureType.getAttributeDescriptor(attributeName));
2308

    
2309
        try {
2310
            index.fill(background, observer);
2311
        } catch (FeatureIndexException e) {
2312
            throw new InitializeException(index.getName(), e);
2313
        }
2314

    
2315
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2316
        return index;
2317
    }
2318

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

    
2324
    @Override
2325
    public FeatureStoreTransforms getTransforms() {
2326
        return this.transforms;
2327
    }
2328

    
2329
    @Override
2330
    public FeatureQuery createFeatureQuery() {
2331
        return new DefaultFeatureQuery();
2332
    }
2333

    
2334
    @Override
2335
    public DataQuery createQuery() {
2336
        return createFeatureQuery();
2337
    }
2338

    
2339
    //
2340
    // ====================================================================
2341
    // UndoRedo related methods
2342
    //
2343

    
2344
    @Override
2345
    public boolean canRedo() {
2346
        return commands.canRedo();
2347
    }
2348

    
2349
    @Override
2350
    public boolean canUndo() {
2351
        return commands.canUndo();
2352
    }
2353

    
2354
    @Override
2355
    public void redo(int num) throws RedoException {
2356
        for (int i = 0; i < num; i++) {
2357
            redo();
2358
        }
2359
    }
2360

    
2361
    @Override
2362
    public void undo(int num) throws UndoException {
2363
        for (int i = 0; i < num; i++) {
2364
            undo();
2365
        }
2366
    }
2367

    
2368
    //
2369
    // ====================================================================
2370
    // Metadata related methods
2371
    //
2372

    
2373
    @Override
2374
    public Object getMetadataID() {
2375
        return this.provider.getSourceId();
2376
    }
2377

    
2378
    @Override
2379
    public void delegate(DynObject dynObject) {
2380
        this.metadata.delegate(dynObject);
2381
    }
2382

    
2383
    @Override
2384
    public DynClass getDynClass() {
2385
        return this.metadata.getDynClass();
2386
    }
2387

    
2388
    @Override
2389
        public Object getDynValue(String name) throws DynFieldNotFoundException {
2390
                if( this.transforms.hasDynValue(name) ) {
2391
                        return this.transforms.getDynValue(name);
2392
                }
2393
                if (this.metadata.hasDynValue(name)) {
2394
                        return this.metadata.getDynValue(name);
2395
                }
2396
                if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2397
                        return this.provider.getProviderName();
2398
                } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2399
                        return this.provider.getSourceId();
2400
                } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2401
                        try {
2402
                                return this.getDefaultFeatureType();
2403
                        } catch (DataException e) {
2404
                                return null;
2405
                        }
2406
                }
2407
                return this.metadata.getDynValue(name);
2408
        }
2409

    
2410
    @Override
2411
    public boolean hasDynValue(String name) {
2412
                if( this.transforms.hasDynValue(name) ) {
2413
                        return true;
2414
                }
2415
        return this.metadata.hasDynValue(name);
2416
    }
2417

    
2418
    @Override
2419
    public boolean hasDynMethod(String name) {
2420
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2421
    }
2422

    
2423
    @Override
2424
    public void implement(DynClass dynClass) {
2425
        this.metadata.implement(dynClass);
2426
    }
2427

    
2428
    @Override
2429
    public Object invokeDynMethod(String name, Object[] args)
2430
        throws DynMethodException {
2431
        return this.metadata.invokeDynMethod(this, name, args);
2432
    }
2433

    
2434
    @Override
2435
    public Object invokeDynMethod(int code, Object[] args)
2436
        throws DynMethodException {
2437
        return this.metadata.invokeDynMethod(this, code, args);
2438
    }
2439

    
2440
    @Override
2441
    public void setDynValue(String name, Object value)
2442
        throws DynFieldNotFoundException {
2443
                if( this.transforms.hasDynValue(name) ) {
2444
                        this.transforms.setDynValue(name, value);
2445
                        return;
2446
                }
2447
        this.metadata.setDynValue(name, value);
2448

    
2449
    }
2450

    
2451
    /*
2452
     * (non-Javadoc)
2453
     *
2454
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2455
     */
2456
    @Override
2457
    public Set getMetadataChildren() {
2458
        return this.metadataChildren;
2459
    }
2460

    
2461
    /*
2462
     * (non-Javadoc)
2463
     *
2464
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2465
     */
2466
    @Override
2467
    public String getMetadataName() {
2468
        return this.provider.getProviderName();
2469
    }
2470

    
2471
    public FeatureTypeManager getFeatureTypeManager() {
2472
        return this.featureTypeManager;
2473
    }
2474

    
2475
    @Override
2476
    public long getFeatureCount() throws DataException {
2477
        if (featureCount == null) {
2478
            featureCount = this.provider.getFeatureCount();
2479
        }
2480
        if (this.isEditing()) {
2481
            if(this.isAppending()) {
2482
                try{
2483
                    throw new IllegalStateException();
2484
                } catch(IllegalStateException e) {
2485
                    LOG.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
2486
                }
2487
                return -1;
2488
            } else {
2489
                return featureCount
2490
                    + this.featureManager.getDeltaSize();
2491
            }
2492
        }
2493
        return featureCount;
2494
    }
2495

    
2496
    private Long getTemporalOID() {
2497
        return this.temporalOid++;
2498
    }
2499

    
2500
    @Override
2501
    public FeatureType getProviderFeatureType(String featureTypeId) {
2502
        if (featureTypeId == null) {
2503
            return this.defaultFeatureType;
2504
        }
2505
        FeatureType type;
2506
        Iterator iter = this.featureTypes.iterator();
2507
        while (iter.hasNext()) {
2508
            type = (FeatureType) iter.next();
2509
            if (type.getId().equals(featureTypeId)) {
2510
                return type;
2511
            }
2512
        }
2513
        return null;
2514
    }
2515

    
2516
    @Override
2517
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2518
        return ((DefaultFeature) feature).getData();
2519
    }
2520

    
2521
    @Override
2522
    public DataStore getStore() {
2523
        return this;
2524
    }
2525

    
2526
    @Override
2527
    public FeatureStore getFeatureStore() {
2528
        return this;
2529
    }
2530

    
2531
    @Override
2532
    public void createCache(String name, DynObject parameters)
2533
        throws DataException {
2534
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2535
        if (cache == null) {
2536
            throw new CreateException("FeaureCacheProvider", null);
2537
        }
2538
        cache.apply(this, provider);
2539
        provider = cache;
2540

    
2541
        featureCount = null;
2542
    }
2543

    
2544
    @Override
2545
    public FeatureCache getCache() {
2546
        return cache;
2547
    }
2548

    
2549
    @Override
2550
    public void clear() {
2551
        if (metadata != null) {
2552
            metadata.clear();
2553
        }
2554
    }
2555

    
2556
    @Override
2557
    public String getName() {
2558
        if( this.provider != null ) {
2559
            return this.provider.getName();
2560
        }
2561
        if( this.parameters instanceof HasAFile ) {
2562
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
2563
        }
2564
        return "unknow";
2565
    }
2566

    
2567
    @Override
2568
    public String getFullName() {
2569
        try {
2570
            if( this.provider!=null ) {
2571
                return this.provider.getFullName();
2572
            }
2573
            if( this.parameters instanceof HasAFile ) {
2574
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
2575
            }
2576
            return null;
2577
        } catch(Throwable th) {
2578
            return null;
2579
        }
2580
    }
2581

    
2582
    @Override
2583
    public String getProviderName() {
2584
        if( this.provider!=null ) {
2585
            return this.provider.getProviderName();
2586
        }
2587
        if( this.parameters != null ) {
2588
            return this.parameters.getDataStoreName();
2589
        }
2590
        return null;
2591

    
2592
    }
2593

    
2594
    @Override
2595
    public boolean isKnownEnvelope() {
2596
        return this.provider.isKnownEnvelope();
2597
    }
2598

    
2599
    @Override
2600
    public boolean hasRetrievedFeaturesLimit() {
2601
        return this.provider.hasRetrievedFeaturesLimit();
2602
    }
2603

    
2604
    @Override
2605
    public int getRetrievedFeaturesLimit() {
2606
        return this.provider.getRetrievedFeaturesLimit();
2607
    }
2608

    
2609
    @Override
2610
    public Interval getInterval() {
2611
        if( this.timeSupport!=null ) {
2612
            return this.timeSupport.getInterval();
2613
        }
2614
        return this.provider.getInterval();
2615
    }
2616

    
2617
    @Override
2618
    public Collection getTimes() {
2619
        if( this.timeSupport!=null ) {
2620
            return this.timeSupport.getTimes();
2621
        }
2622
        return this.provider.getTimes();
2623
    }
2624

    
2625
    @Override
2626
    public Collection getTimes(Interval interval) {
2627
        if( this.timeSupport!=null ) {
2628
            return this.timeSupport.getTimes(interval);
2629
        }
2630
        return this.provider.getTimes(interval);
2631
    }
2632

    
2633
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
2634
        if( this.isEditing() ) {
2635
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
2636
        }
2637
        if( !this.transforms.isEmpty() ) {
2638
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
2639
        }
2640
        FeatureType ft = this.defaultFeatureType;
2641
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
2642
        if( attr == null ) {
2643
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
2644
        }
2645
        EditableFeatureType eft = ft.getEditable();
2646
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
2647
        if( attr != null ) {
2648
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
2649
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
2650
            }
2651
            eft.remove(attr.getName());
2652
        }
2653
        EditableFeatureAttributeDescriptor attrTime = eft.add(
2654
            timeSupport.getAttributeName(), 
2655
            timeSupport.getDataType()
2656
        );
2657
        attrTime.setIsTime(true);
2658
        attrTime.setFeatureAttributeEmulator(timeSupport);
2659
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
2660
        this.defaultFeatureType = eft.getNotEditableCopy();
2661
        
2662
        this.timeSupport = timeSupport;
2663
    }
2664

    
2665
    @Override
2666
    @SuppressWarnings("CloneDoesntCallSuperClone")
2667
    public Object clone() throws CloneNotSupportedException {
2668

    
2669
        DataStoreParameters dsp = getParameters();
2670

    
2671
        DefaultFeatureStore cloned_store = null;
2672

    
2673
        try {
2674
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2675
                openStore(this.getProviderName(), dsp);
2676
            if (transforms != null) {
2677
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2678
                cloned_store.transforms.setStoreForClone(cloned_store);
2679
            }
2680
        } catch (Exception e) {
2681
            throw new CloneException(e);
2682
        }
2683
        return cloned_store;
2684

    
2685
    }
2686

    
2687
    @Override
2688
    public Feature getFeature(DynObject dynobject) {
2689
        if (dynobject instanceof DynObjectFeatureFacade){
2690
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2691
            return f;
2692
        }
2693
        return null;
2694
    }
2695

    
2696
    @Override
2697
    public Iterator iterator() {
2698
        try {
2699
            return this.getFeatureSet().fastIterator();
2700
        } catch (DataException ex) {
2701
            throw new RuntimeException(ex);
2702
        }
2703
    }
2704

    
2705
    @Override
2706
    public ExpressionBuilder createExpressionBuilder() {
2707
        if( this.provider instanceof FeatureStoreProvider_v2 ) {
2708
            return ((FeatureStoreProvider_v2)this.provider).createExpression();
2709
        }
2710
        return new SQLBuilderBase();
2711
    }
2712

    
2713
    @Override
2714
    public ExpressionBuilder createExpression() {
2715
        return createExpressionBuilder();
2716
    }
2717

    
2718
    public FeatureSet features() throws DataException {
2719
        // This is to avoid jython to create a property with this name
2720
        // to access method getFeatures.
2721
        return this.getFeatureSet();
2722
    }
2723

    
2724
    @Override
2725
    public DataStoreProviderFactory getProviderFactory() {
2726
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
2727
        return factory;
2728
    }
2729

    
2730
    @Override
2731
    public void useCache(String providerName, DynObject parameters) throws DataException {
2732
        throw new UnsupportedOperationException();
2733
    }
2734

    
2735
    @Override
2736
    public boolean isBroken() {
2737
        return this.state.isBroken();
2738
    }
2739

    
2740
    @Override
2741
    public Throwable getBreakingsCause() {
2742
            return this.state.getBreakingsCause();
2743
    }
2744

    
2745
    @Override
2746
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
2747
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
2748
      if( !factory.supportNumericOID() ) {
2749
          return null;
2750
      }
2751
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
2752
      return wrappedIndex;
2753
  }
2754

    
2755
    @Override
2756
    public FeatureReference getFeatureReference(String code) {
2757
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
2758
        return featureReference;
2759
    }
2760
}