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

History | View | Annotate | Download (79.7 KB)

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

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

    
27
import org.gvsig.fmap.dal.feature.spi.SQLBuilderBase;
28

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

    
41
import org.cresques.cts.IProjection;
42

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

    
157
import org.slf4j.Logger;
158
import org.slf4j.LoggerFactory;
159

    
160
public class DefaultFeatureStore extends AbstractDisposable implements
161
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
162

    
163
    private static final Logger LOG = LoggerFactory
164
        .getLogger(DefaultFeatureStore.class);
165

    
166
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
167

    
168
    private DataStoreParameters parameters = null;
169
    private FeatureSelection selection;
170
    private FeatureLocks locks;
171

    
172
    private DelegateWeakReferencingObservable delegateObservable =
173
        new DelegateWeakReferencingObservable(this);
174

    
175
    private FeatureCommandsStack commands;
176
    private FeatureTypeManager featureTypeManager;
177
    private FeatureManager featureManager;
178
    private SpatialManager spatialManager;
179

    
180
    private FeatureType defaultFeatureType = null;
181
    private List featureTypes = new ArrayList();
182

    
183
    private int mode = MODE_QUERY;
184
    private long versionOfUpdate = 0;
185
    private boolean hasStrongChanges = true;
186
    private boolean hasInserts = true;
187

    
188
    private DefaultDataManager dataManager = null;
189

    
190
    private FeatureStoreProvider provider = null;
191

    
192
    private DefaultFeatureIndexes indexes;
193

    
194
    private DefaultFeatureStoreTransforms transforms;
195

    
196
    DelegatedDynObject metadata;
197

    
198
    private Set metadataChildren;
199

    
200
    private Long featureCount = null;
201

    
202
    private long temporalOid = 0;
203

    
204
    private FeatureCacheProvider cache;
205

    
206
    FeatureStoreTimeSupport timeSupport;
207
    /*
208
     * TODO:
209
     *
210
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
211
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
212
     * featureType al que se le han cambiado las reglas de validacion cuando
213
     * hasStrongChanges=false.
214
     */
215

    
216
    public DefaultFeatureStore() {
217

    
218
    }
219

    
220
    @Override
221
    public void intialize(DataManager dataManager,
222
        DataStoreParameters parameters) throws InitializeException {
223

    
224
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
225

    
226
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
227
            FeatureStore.METADATA_DEFINITION_NAME,
228
            MetadataManager.METADATA_NAMESPACE
229
        );
230

    
231
        this.dataManager = (DefaultDataManager) dataManager;
232

    
233
        this.parameters = parameters;
234
        this.transforms = new DefaultFeatureStoreTransforms(this);
235
        try {
236
            indexes = new DefaultFeatureIndexes(this);
237
        } catch (DataException e) {
238
            throw new InitializeException(e);
239
        }
240

    
241
    }
242

    
243
    @Override
244
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
245
        this.provider = (FeatureStoreProvider) provider;
246
        this.delegate((DynObject) provider);
247
        this.metadataChildren = new HashSet();
248
        this.metadataChildren.add(provider);
249
    }
250

    
251
    public DataStoreParameters getParameters() {
252
        return parameters;
253
    }
254

    
255
    public int getMode() {
256
        return this.mode;
257
    }
258

    
259
    public DataManager getManager() {
260
        return this.dataManager;
261
    }
262

    
263
    public Iterator getChildren() {
264
        return this.provider.getChilds();
265
    }
266

    
267
    public FeatureStoreProvider getProvider() {
268
        return this.provider;
269
    }
270

    
271
    public FeatureManager getFeatureManager() {
272
        return this.featureManager;
273
    }
274

    
275
    public void setFeatureTypes(List types, FeatureType defaultType) {
276
        this.featureTypes = types;
277
        this.defaultFeatureType = defaultType;
278
    }
279

    
280
    public void open() throws OpenException {
281
        if (this.mode != MODE_QUERY) {
282
            // TODO: Se puede hacer un open estando en edicion ?
283
            try {
284
                throw new IllegalStateException();
285
            } catch(Exception ex) {
286
                LOG.warn("Opening a store in editing/append mode ("+this.getFullName()+").",ex);
287
            }
288
        }
289
        this.notifyChange(DataStoreNotification.BEFORE_OPEN);
290
        this.provider.open();
291
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
292
    }
293

    
294
    public void refresh() throws OpenException, InitializeException {
295
        if (this.mode != MODE_QUERY) {
296
            throw new IllegalStateException();
297
        }
298
        this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH);
299
        this.featureCount = null;
300
        this.provider.refresh();
301
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
302
    }
303

    
304
    public void close() throws CloseException {
305
        if (this.mode != MODE_QUERY) {
306
            // TODO: Se puede hacer un close estando en edicion ?
307
            try {
308
                throw new IllegalStateException();
309
            } catch(Exception ex) {
310
                LOG.warn("Clossing a store in editing/append mode ("+this.getFullName()+").",ex);
311
            }
312
        }
313
        this.notifyChange(DataStoreNotification.BEFORE_CLOSE);
314
        this.featureCount = null;
315
        this.provider.close();
316
        this.notifyChange(DataStoreNotification.AFTER_CLOSE);
317
    }
318

    
319
    protected void doDispose() throws BaseException {
320
        if (this.mode != MODE_QUERY) {
321
            // TODO: Se puede hacer un dispose estando en edicion ?
322
            try {
323
                throw new IllegalStateException();
324
            } catch(Exception ex) {
325
                LOG.warn("Dispossing a store in editing/append mode ("+this.getFullName()+").",ex);
326
            }
327
        }
328
        this.notifyChange(DataStoreNotification.BEFORE_DISPOSE);
329
        this.disposeIndexes();
330
        this.provider.dispose();
331
        if (this.selection != null) {
332
            this.selection.dispose();
333
            this.selection = null;
334
        }
335
        this.commands = null;
336
        this.featureCount = null;
337
        if (this.locks != null) {
338
            // this.locks.dispose();
339
            this.locks = null;
340
        }
341

    
342
        if (this.featureTypeManager != null) {
343
            this.featureTypeManager.dispose();
344
            this.featureTypeManager = null;
345
        }
346

    
347
        this.featureManager = null;
348
        this.spatialManager = null;
349

    
350
        this.parameters = null;
351
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
352
        if (delegateObservable != null) {
353
            this.delegateObservable.deleteObservers();
354
            this.delegateObservable = null;
355
        }
356
    }
357

    
358
    public boolean allowWrite() {
359
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
360
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
361
            return false;
362
        }
363
        return this.provider.allowWrite();
364
    }
365

    
366
    public boolean canWriteGeometry(int geometryType) throws DataException {
367
        return this.provider.canWriteGeometry(geometryType, 0);
368
    }
369

    
370
    public DataServerExplorer getExplorer() throws ReadException,
371
        ValidateDataParametersException {
372
        return this.provider.getExplorer();
373
    }
374

    
375
    /*
376
     * public Metadata getMetadata() throws MetadataNotFoundException {
377
     * // TODO:
378
     * // Si el provider devuelbe null habria que ver de construir aqui
379
     * // los metadatos basicos, como el Envelope y el SRS.
380
     *
381
     * // TODO: Estando en edicion el Envelope deberia de
382
     * // actualizarse usando el spatialManager
383
     * return this.provider.getMetadata();
384
     * }
385
     */
386

    
387
    public Envelope getEnvelope() throws DataException {
388
        if (this.mode == MODE_FULLEDIT) {
389
                // Just in case another thread tries to write in the store
390
                synchronized (this) {
391
                        return this.spatialManager.getEnvelope();
392
                        }
393
        }
394
        if (hasDynValue(DataStore.METADATA_ENVELOPE)){
395
            return (Envelope)getDynValue(DataStore.METADATA_ENVELOPE);
396
        }
397
        return this.provider.getEnvelope();
398
    }
399

    
400
    /**
401
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
402
     */
403
    public IProjection getSRSDefaultGeometry() throws DataException {
404
        return this.getDefaultFeatureType().getDefaultSRS();
405
    }
406

    
407
    public FeatureSelection createDefaultFeatureSelection()
408
        throws DataException {
409
        return new DefaultFeatureSelection(this);
410
    }
411

    
412
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
413
        throws DataException {
414
        if (type.hasOID()) {
415
            return new DefaultFeatureProvider(type,
416
                this.provider.createNewOID());
417
        }
418
        return new DefaultFeatureProvider(type);
419
    }
420

    
421
    public void saveToState(PersistentState state) throws PersistenceException {
422
        /*if (this.mode != FeatureStore.MODE_QUERY) {
423
            throw new PersistenceException(new IllegalStateException(
424
                this.getName()));
425
        }*/
426
        state.set("dataStoreName", this.getName());
427
        state.set("parameters", this.parameters);
428
        state.set("selection", this.selection);
429
        state.set("transforms", this.transforms);
430
        // TODO locks persistence
431
        // state.set("locks", this.locks);
432
        // TODO indexes persistence
433
        // state.set("indexes", this.indexes);
434
        Map evaluatedAttr = new HashMap(1);
435
        Iterator iterType = featureTypes.iterator();
436
        Iterator iterAttr;
437
        FeatureType type;
438
        DefaultFeatureAttributeDescriptor attr;
439
        List attrs;
440
        while (iterType.hasNext()) {
441
            type = (FeatureType) iterType.next();
442
            attrs = new ArrayList();
443
            iterAttr = type.iterator();
444
            while (iterAttr.hasNext()) {
445
                attr = (DefaultFeatureAttributeDescriptor) iterAttr.next();
446
                if ((attr.getEvaluator() != null)
447
                    && (attr.getEvaluator() instanceof Persistent)) {
448
                    attrs.add(attr);
449
                }
450
            }
451
            if (!attrs.isEmpty()) {
452
                evaluatedAttr.put(type.getId(), attrs);
453
            }
454

    
455
        }
456

    
457
        if (evaluatedAttr.isEmpty()) {
458
            evaluatedAttr = null;
459
        }
460

    
461
        state.set("evaluatedAttributes", evaluatedAttr);
462
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
463

    
464
    }
465

    
466
    public void loadFromState(PersistentState state)
467
        throws PersistenceException {
468
        if (this.provider != null) {
469
            throw new PersistenceStoreAlreadyLoadedException(this.getName());
470
        }
471
        if (this.getManager() == null) {
472
            this.dataManager = (DefaultDataManager) DALLocator.getDataManager();
473
        }
474

    
475
        DataStoreParameters params =
476
            (DataStoreParameters) state.get("parameters");
477

    
478
        DataStoreProvider prov;
479
        try {
480
            this.intialize(this.dataManager, params);
481
            prov = this.dataManager.createProvider(
482
                    (DataStoreProviderServices) this,
483
                    params
484
            );
485
            this.setProvider(prov);
486

    
487
            this.selection = (FeatureSelection) state.get("selection");
488
            this.transforms =
489
                (DefaultFeatureStoreTransforms) state.get("transforms");
490
            Map evaluatedAttributes = (Map) state.get("evaluatedAttributes");
491
            if ((evaluatedAttributes != null) && !evaluatedAttributes.isEmpty()) {
492
                List attrs;
493
                Iterator iterEntries =
494
                    evaluatedAttributes.entrySet().iterator();
495
                Entry entry;
496
                while (iterEntries.hasNext()) {
497
                    entry = (Entry) iterEntries.next();
498
                    attrs = (List) entry.getValue();
499
                    if (attrs.isEmpty()) {
500
                        continue;
501
                    }
502
                    int fTypePos = -1;
503
                    DefaultFeatureType type = null;
504
                    for (int i = 0; i < featureTypes.size(); i++) {
505
                        type = (DefaultFeatureType) featureTypes.get(i);
506
                        if (type.getId().equals(entry.getKey())) {
507
                            fTypePos = i;
508
                            break;
509
                        }
510
                    }
511
                    if (fTypePos < 0) {
512
                        throw new PersistenceCantFindFeatureTypeException(
513
                            this.getName(), (String) entry.getKey());
514
                    }
515
                    DefaultEditableFeatureType eType =
516
                        (DefaultEditableFeatureType) type.getEditable();
517
                    Iterator iterAttr = attrs.iterator();
518
                    FeatureAttributeDescriptor attr;
519
                    while (iterAttr.hasNext()) {
520
                        attr = (FeatureAttributeDescriptor) iterAttr.next();
521
                        eType.addLike(attr);
522
                    }
523
                    featureTypes.set(fTypePos, eType.getNotEditableCopy());
524

    
525
                }
526

    
527
            }
528

    
529
            String defFTypeid = state.getString("defaultFeatureTypeId");
530
            FeatureType ftype = null;
531

    
532
            if (this.defaultFeatureType == null ||
533
                this.defaultFeatureType.getId() == null ||
534
                !this.defaultFeatureType.getId().equals(
535
                state.getString("defaultFeatureTypeId"))) {
536

    
537
                ftype = getFeatureType(defFTypeid);
538
                if (ftype == null) {
539
                        /*
540
                         * Un error en el m?todo de PostgresQL getName(), hace que
541
                         * el nombre del featureType sea valor retornado por el getProviderName()
542
                         * De momento se pone este parche para apa?arlo y poder mantener compatibilidad
543
                         * con proyectos antiguos (2.1 y 2.2)
544
                         */
545
                        ftype = getFeatureType(prov.getName());
546
                        if(ftype == null){
547
                                throw new PersistenceCantFindDefaultFeatureTypeException(
548
                                                this.getName(), defFTypeid);
549
                        }
550
                }
551
                this.defaultFeatureType = ftype;
552
            }
553
            LOG.info("loadFromState() {} {}.", prov.getProviderName(), parameters.toString());
554

    
555
        } catch (InitializeException e) {
556
            throw new PersistenceException(e);
557
        } catch (DataException e) {
558
            throw new PersistenceException(e);
559
        }
560

    
561
    }
562

    
563
    public static void registerPersistenceDefinition() {
564
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
565
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
566
            DynStruct definition =
567
                manager.addDefinition(DefaultFeatureStore.class,
568
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
569
                        + " Persistent definition", null, null);
570
            definition.addDynFieldString("dataStoreName").setMandatory(true)
571
                .setPersistent(true);
572

    
573
            definition.addDynFieldObject("parameters")
574
                .setClassOfValue(DynObject.class).setMandatory(true)
575
                .setPersistent(true);
576

    
577
            definition.addDynFieldObject("selection")
578
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
579
                .setPersistent(true);
580

    
581
            definition.addDynFieldObject("transforms")
582
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
583
                .setMandatory(true).setPersistent(true);
584

    
585
            definition.addDynFieldMap("evaluatedAttributes")
586
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
587
                .setMandatory(false).setPersistent(true);
588

    
589
            definition.addDynFieldString("defaultFeatureTypeId")
590
                .setMandatory(true).setPersistent(true);
591
        }
592
    }
593

    
594
    public static void registerMetadataDefinition() throws MetadataException {
595
        MetadataManager manager = MetadataLocator.getMetadataManager();
596
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
597
            DynStruct metadataDefinition =
598
                manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
599
            metadataDefinition.extend(manager
600
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
601
        }
602
    }
603

    
604
    //
605
    // ====================================================================
606
    // Gestion de la seleccion
607
    //
608

    
609
    public void setSelection(DataSet selection) throws DataException {
610
        this.setSelection((FeatureSet) selection);
611
    }
612

    
613
    public DataSet createSelection() throws DataException {
614
        return createFeatureSelection();
615
    }
616

    
617
    public DataSet getSelection() throws DataException {
618
        return this.getFeatureSelection();
619
    }
620

    
621
    public void setSelection(FeatureSet selection) throws DataException {
622
        setSelection(selection, true);
623
    }
624

    
625
    /**
626
     * @see #setSelection(FeatureSet)
627
     * @param undoable
628
     *            if the action must be undoable
629
     */
630
    public void setSelection(FeatureSet selection, boolean undoable)
631
        throws DataException {
632
        if (selection == null) {
633
            if (undoable) {
634
                throw new SelectionNotAllowedException(getName());
635
            }
636

    
637
        } else {
638
            if (selection.equals(this.selection)) {
639
                return;
640
            }
641
            if (!selection.isFromStore(this)) {
642
                throw new SelectionNotAllowedException(getName());
643
            }
644
        }
645

    
646
        if (this.selection != null) {
647
            this.selection.deleteObserver(this);
648
        }
649
        if (selection == null) {
650
            if (this.selection != null) {
651
                this.selection.dispose();
652
            }
653
            this.selection = null;
654
            return;
655
        }
656
        if (selection instanceof FeatureSelection) {
657
            if (undoable && isEditing()) {
658
                commands.selectionSet(this, this.selection,
659
                    (FeatureSelection) selection);
660
            }
661
            if (this.selection != null) {
662
                this.selection.dispose();
663
            }
664
            this.selection = (FeatureSelection) selection;
665
        } else {
666
            if (undoable && isEditing()) {
667
                commands.startComplex("_selectionSet");
668
            }
669
            if (selection instanceof DefaultFeatureSelection) {
670
                DefaultFeatureSelection defSelection =
671
                    (DefaultFeatureSelection) selection;
672
                defSelection.deselectAll(undoable);
673
                defSelection.select(selection, undoable);
674
            } else {
675
                this.selection.deselectAll();
676
                this.selection.select(selection);
677
            }
678
            if (undoable && isEditing()) {
679
                commands.endComplex();
680
            }
681
        }
682
        this.selection.addObserver(this);
683

    
684
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
685
    }
686

    
687
    public FeatureSelection createFeatureSelection() throws DataException {
688
        return this.provider.createFeatureSelection();
689
    }
690

    
691
    public FeatureSelection getFeatureSelection() throws DataException {
692
        if (selection == null) {
693
            this.selection = createFeatureSelection();
694
            this.selection.addObserver(this);
695
        }
696
        return selection;
697
    }
698

    
699
    //
700
    // ====================================================================
701
    // Gestion de notificaciones
702
    //
703

    
704
    @Override
705
    public void notifyChange(FeatureStoreNotification storeNotification) {
706
        try {
707
            delegateObservable.notifyObservers(storeNotification);
708
        } catch (Throwable ex) {
709
            LOG.warn("Problems notifying changes in the store '"+this.getName()+" ("+storeNotification.getType()+").",ex);
710
        }
711
    }
712

    
713
    @Override
714
    public void notifyChange(String notification) {
715
        if (delegateObservable != null) {
716
            notifyChange(new DefaultFeatureStoreNotification(this, notification));
717
        }
718

    
719
    }
720

    
721
    @Override
722
    public void notifyChange(String notification, FeatureProvider data) {
723
        Feature f = null;
724
        try {
725
            f = createFeature(data);
726
        } catch (Throwable ex) {
727
            LOG.warn("Problems creating a feature to notifying changes in the store '"+this.getName()+" ("+notification+").",ex);
728
        }
729
        notifyChange(notification, f);
730
    }
731

    
732
    public void notifyChange(String notification, Feature feature) {
733
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
734
            feature));
735
    }
736

    
737
    public void notifyChange(String notification, Command command) {
738
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
739
            command));
740
    }
741

    
742
    public void notifyChange(String notification, EditableFeatureType type) {
743
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
744
            type));
745
    }
746

    
747
    @Override
748
    public void notifyChange(String notification, Resource resource) {
749
        notifyChange(new DefaultFeatureStoreNotification(this,
750
            DataStoreNotification.RESOURCE_CHANGED));
751
    }
752

    
753
    //
754
    // ====================================================================
755
    // Gestion de bloqueos
756
    //
757

    
758
    public boolean isLocksSupported() {
759
        return this.provider.isLocksSupported();
760
    }
761

    
762
    public FeatureLocks getLocks() throws DataException {
763
        if (!this.provider.isLocksSupported()) {
764
            LOG.warn("Locks not supported");
765
            return null;
766
        }
767
        if (locks == null) {
768
            this.locks = this.provider.createFeatureLocks();
769
        }
770
        return locks;
771
    }
772

    
773
    //
774
    // ====================================================================
775
    // Interface Observable
776
    //
777

    
778
    public void disableNotifications() {
779
        this.delegateObservable.disableNotifications();
780

    
781
    }
782

    
783
    public void enableNotifications() {
784
        this.delegateObservable.enableNotifications();
785
    }
786

    
787
    public void beginComplexNotification() {
788
        this.delegateObservable.beginComplexNotification();
789

    
790
    }
791

    
792
    public void endComplexNotification() {
793
        this.delegateObservable.endComplexNotification();
794

    
795
    }
796

    
797
    public void addObserver(Observer observer) {
798
        if (delegateObservable != null) {
799
            this.delegateObservable.addObserver(observer);
800
        }
801
    }
802

    
803
    public void deleteObserver(Observer observer) {
804
        if (delegateObservable != null) {
805
            this.delegateObservable.deleteObserver(observer);
806
        }
807
    }
808

    
809
    public void deleteObservers() {
810
        this.delegateObservable.deleteObservers();
811

    
812
    }
813

    
814
    //
815
    // ====================================================================
816
    // Interface Observer
817
    //
818
    // Usado para observar:
819
    // - su seleccion
820
    // - sus bloqueos
821
    // - sus recursos
822
    //
823

    
824
    public void update(Observable observable, Object notification) {
825
        if (observable instanceof FeatureSet) {
826
            if (observable == this.selection) {
827
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
828
            } else
829
                if (observable == this.locks) {
830
                    this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
831
                }
832

    
833
        } else
834
            if (observable instanceof FeatureStoreProvider) {
835
                if (observable == this.provider) {
836

    
837
                }
838

    
839
            }
840
    }
841

    
842
    //
843
    // ====================================================================
844
    // Edicion
845
    //
846

    
847
    private void newVersionOfUpdate() {
848
        this.versionOfUpdate++;
849
    }
850

    
851
    private long currentVersionOfUpdate() {
852
        return this.versionOfUpdate;
853
    }
854

    
855
    private void checkInEditingMode() throws NeedEditingModeException {
856
        if (mode != MODE_FULLEDIT) {
857
            throw new NeedEditingModeException(this.getName());
858
        }
859
    }
860

    
861
    private void checkNotInAppendMode() throws IllegalStateException {
862
        if (mode == MODE_APPEND) {
863
                        throw new IllegalStateException("Error: store "
864
                                        + this.getFullName() + " is in append mode");
865
        }
866
    }
867

    
868
    private void checkIsOwnFeature(Feature feature)
869
        throws IllegalFeatureException {
870
        if (((DefaultFeature) feature).getStore() != this) {
871
            throw new IllegalFeatureException(this.getName());
872
        }
873
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
874
        // fixFeatureType((DefaultFeatureType) feature.getType());
875
    }
876

    
877
    private void exitEditingMode() {
878
        if (commands != null) {
879
            commands.clear();
880
            commands = null;
881
        }
882

    
883
        if (featureTypeManager != null) {
884
            featureTypeManager.dispose();
885
            featureTypeManager = null;
886

    
887
        }
888

    
889
        // TODO implementar un dispose para estos dos
890
        featureManager = null;
891
        spatialManager = null;
892

    
893
        featureCount = null;
894

    
895
        mode = MODE_QUERY;
896
        hasStrongChanges = true; // Lo deja a true por si las moscas
897
        hasInserts = true;
898
    }
899

    
900
    synchronized public void edit() throws DataException {
901
        edit(MODE_FULLEDIT);
902
    }
903

    
904
    synchronized public void edit(int mode) throws DataException {
905
        LOG.debug("Starting editing in mode: {}", new Integer(mode));
906
        try {
907
            if (this.mode != MODE_QUERY) {
908
                throw new AlreadyEditingException(this.getName());
909
            }
910
            if (!this.provider.supportsAppendMode()) {
911
                mode = MODE_FULLEDIT;
912
            }
913
            switch (mode) {
914
            case MODE_QUERY:
915
                throw new IllegalStateException(this.getName());
916

    
917
            case MODE_FULLEDIT:
918
                if (!this.transforms.isEmpty()) {
919
                    throw new IllegalStateException(this.getName());
920
                }
921
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
922
                invalidateIndexes();
923
                featureManager =
924
                    new FeatureManager(new MemoryExpansionAdapter());
925
                featureTypeManager =
926
                    new FeatureTypeManager(this, new MemoryExpansionAdapter());
927
                spatialManager =
928
                    new SpatialManager(this, provider.getEnvelope());
929

    
930
                commands =
931
                    new DefaultFeatureCommandsStack(this, featureManager,
932
                        spatialManager, featureTypeManager);
933
                this.mode = MODE_FULLEDIT;
934
                hasStrongChanges = false;
935
                hasInserts = false;
936
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
937
                break;
938
            case MODE_APPEND:
939
                if (!this.transforms.isEmpty()) {
940
                    throw new IllegalStateException(this.getName());
941
                }
942
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
943
                invalidateIndexes();
944
                this.provider.beginAppend();
945
                this.mode = MODE_APPEND;
946
                hasInserts = false;
947
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
948
                break;
949
            }
950
        } catch (Exception e) {
951
            throw new StoreEditException(e, this.getName());
952
        }
953
    }
954

    
955
    private void invalidateIndexes() {
956
        setIndexesValidStatus(false);
957
    }
958

    
959
    private void setIndexesValidStatus(boolean valid) {
960
        FeatureIndexes indexes = getIndexes();
961
        LOG.debug("Setting the store indexes to valid status {}: {}", (valid
962
            ? Boolean.TRUE : Boolean.FALSE), indexes);
963
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
964
            FeatureIndex index = (FeatureIndex) iterator.next();
965
            if (index instanceof FeatureIndexProviderServices) {
966
                FeatureIndexProviderServices indexServices =
967
                    (FeatureIndexProviderServices) index;
968
                indexServices.setValid(valid);
969
            }
970
        }
971
    }
972

    
973
    private void updateIndexes() throws FeatureIndexException {
974
        FeatureIndexes indexes = getIndexes();
975
        LOG.debug("Refilling indexes: {}", indexes);
976
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
977
            FeatureIndex index = (FeatureIndex) iterator.next();
978
            if (index instanceof FeatureIndexProviderServices) {
979
                FeatureIndexProviderServices indexServices =
980
                    (FeatureIndexProviderServices) index;
981
                indexServices.fill(true, null);
982
            }
983
        }
984
    }
985

    
986
    private void waitForIndexes() {
987
        FeatureIndexes indexes = getIndexes();
988
        LOG.debug("Waiting for indexes to finish filling: {}", indexes);
989
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
990
            FeatureIndex index = (FeatureIndex) iterator.next();
991
            if (index instanceof FeatureIndexProviderServices) {
992
                FeatureIndexProviderServices indexServices =
993
                    (FeatureIndexProviderServices) index;
994
                indexServices.waitForIndex();
995
            }
996
        }
997
    }
998

    
999
    private void disposeIndexes() {
1000
        FeatureIndexes indexes = getIndexes();
1001
        LOG.debug("Disposing indexes: {}", indexes);
1002
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
1003
            FeatureIndex index = (FeatureIndex) iterator.next();
1004
            if (index instanceof FeatureIndexProviderServices) {
1005
                FeatureIndexProviderServices indexServices =
1006
                    (FeatureIndexProviderServices) index;
1007
                indexServices.dispose();
1008
            }
1009
        }
1010
    }
1011

    
1012
    public boolean isEditing() {
1013
        return mode == MODE_FULLEDIT;
1014
    }
1015

    
1016
    public boolean isAppending() {
1017
        return mode == MODE_APPEND;
1018
    }
1019

    
1020
    synchronized public void update(EditableFeatureType type)
1021
        throws DataException {
1022
        try {
1023
            checkInEditingMode();
1024
            if (type == null) {
1025
                throw new NullFeatureTypeException(getName());
1026
            }
1027
            // FIXME: Comprobar que es un featureType aceptable.
1028
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
1029
            newVersionOfUpdate();
1030

    
1031
            FeatureType oldt = type.getSource().getCopy();
1032
            FeatureType newt = type.getCopy();
1033
            commands.update(newt, oldt);
1034

    
1035
            if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
1036
                hasStrongChanges = true;
1037
            }
1038
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1039
        } catch (Exception e) {
1040
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1041
        }
1042
    }
1043

    
1044
    public void delete(Feature feature) throws DataException {
1045
        this.commands.delete(feature);
1046
    }
1047

    
1048
    synchronized public void doDelete(Feature feature) throws DataException {
1049
        try {
1050
            checkInEditingMode();
1051
            checkIsOwnFeature(feature);
1052
            if (feature instanceof EditableFeature) {
1053
                throw new StoreDeleteEditableFeatureException(getName());
1054
            }
1055
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1056

    
1057
            //Update the featureManager and the spatialManager
1058
            featureManager.delete(feature.getReference());
1059
            spatialManager.deleteFeature(feature);
1060

    
1061
            newVersionOfUpdate();
1062
            hasStrongChanges = true;
1063
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1064
        } catch (Exception e) {
1065
            throw new StoreDeleteFeatureException(e, this.getName());
1066
        }
1067
    }
1068

    
1069
    private static EditableFeature lastChangedFeature = null;
1070

    
1071
    public synchronized void insert(EditableFeature feature)
1072
        throws DataException {
1073
        LOG.debug("In editing mode {}, insert feature: {}", new Integer(mode),
1074
            feature);
1075
        try {
1076
            switch (mode) {
1077
            case MODE_QUERY:
1078
                throw new NeedEditingModeException(this.getName());
1079

    
1080
            case MODE_APPEND:
1081
                checkIsOwnFeature(feature);
1082
                if (feature.getSource() != null) {
1083
                    throw new NoNewFeatureInsertException(this.getName());
1084
                }
1085
                this.featureCount = null;
1086
                notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1087
                feature.validate(Feature.UPDATE);
1088
                provider.append(((DefaultEditableFeature) feature).getData());
1089
                hasStrongChanges = true;
1090
                hasInserts = true;
1091
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1092
                break;
1093

    
1094
            case MODE_FULLEDIT:
1095
                if (feature.getSource() != null) {
1096
                    throw new NoNewFeatureInsertException(this.getName());
1097
                }
1098
                commands.insert(feature);
1099
            }
1100
        } catch (Exception e) {
1101
            throw new StoreInsertFeatureException(e, this.getName());
1102
        }
1103
    }
1104

    
1105
    synchronized public void doInsert(EditableFeature feature)
1106
        throws DataException {
1107
        checkIsOwnFeature(feature);
1108

    
1109
        waitForIndexes();
1110

    
1111
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1112
        newVersionOfUpdate();
1113
        if ((lastChangedFeature == null)
1114
            || (lastChangedFeature.getSource() != feature.getSource())) {
1115
            lastChangedFeature = feature;
1116
            feature.validate(Feature.UPDATE);
1117
            lastChangedFeature = null;
1118
        }
1119
        //Update the featureManager and the spatialManager
1120
        ((DefaultEditableFeature) feature).setInserted(true);
1121
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1122

    
1123

    
1124
        featureManager.add(newFeature);
1125
        spatialManager.insertFeature(newFeature);
1126

    
1127
        hasStrongChanges = true;
1128
        hasInserts = true;
1129
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1130
    }
1131

    
1132
    public void update(EditableFeature feature)
1133
    throws DataException {
1134
        if ((feature).getSource() == null) {
1135
            insert(feature);
1136
            return;
1137
        }
1138
        commands.update(feature, feature.getSource());
1139
    }
1140

    
1141
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1142
        throws DataException {
1143
        try {
1144
            checkInEditingMode();
1145
            checkIsOwnFeature(feature);
1146
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature);
1147
            newVersionOfUpdate();
1148
            if ((lastChangedFeature == null)
1149
                || (lastChangedFeature.getSource() != feature.getSource())) {
1150
                lastChangedFeature = feature;
1151
                feature.validate(Feature.UPDATE);
1152
                lastChangedFeature = null;
1153
            }
1154

    
1155
            //Update the featureManager and the spatialManager
1156
            Feature newf = feature.getNotEditableCopy();
1157
            featureManager.update(newf, oldFeature);
1158
            spatialManager.updateFeature(newf, oldFeature);
1159

    
1160
            hasStrongChanges = true;
1161
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1162
        } catch (Exception e) {
1163
            throw new StoreUpdateFeatureException(e, this.getName());
1164
        }
1165
    }
1166

    
1167
    synchronized public void redo() throws RedoException {
1168
        Command redo = commands.getNextRedoCommand();
1169
        try {
1170
            checkInEditingMode();
1171
        } catch (NeedEditingModeException ex) {
1172
            throw new RedoException(redo, ex);
1173
        }
1174
        notifyChange(FeatureStoreNotification.BEFORE_REDO, redo);
1175
        newVersionOfUpdate();
1176
        commands.redo();
1177
        hasStrongChanges = true;
1178
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1179
    }
1180

    
1181
    synchronized public void undo() throws UndoException {
1182
        Command undo = commands.getNextUndoCommand();
1183
        try {
1184
            checkInEditingMode();
1185
        } catch (NeedEditingModeException ex) {
1186
            throw new UndoException(undo, ex);
1187
        }
1188
        notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo);
1189
        newVersionOfUpdate();
1190
        commands.undo();
1191
        hasStrongChanges = true;
1192
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1193
    }
1194

    
1195
    public List getRedoInfos() {
1196
        if (isEditing() && (commands != null)) {
1197
            return commands.getRedoInfos();
1198
        } else {
1199
            return null;
1200
        }
1201
    }
1202

    
1203
    public List getUndoInfos() {
1204
        if (isEditing() && (commands != null)) {
1205
            return commands.getUndoInfos();
1206
        } else {
1207
            return null;
1208
        }
1209
    }
1210

    
1211
    public synchronized FeatureCommandsStack getCommandsStack()
1212
        throws DataException {
1213
        checkInEditingMode();
1214
        return commands;
1215
    }
1216

    
1217
    synchronized public void cancelEditing() throws DataException {
1218
        spatialManager.cancelModifies();
1219
        try {
1220
            checkInEditingMode();
1221

    
1222
            boolean clearSelection = this.hasStrongChanges;
1223
            if (this.selection instanceof FeatureReferenceSelection) {
1224
                clearSelection = this.hasInserts;
1225
            }
1226
            notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1227
            exitEditingMode();
1228
            if (clearSelection) {
1229
                ((FeatureSelection) this.getSelection()).deselectAll();
1230
            }
1231
            updateIndexes();
1232
            notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1233
        } catch (Exception e) {
1234
            throw new StoreCancelEditingException(e, this.getName());
1235
        }
1236
    }
1237

    
1238
    synchronized public void finishEditing() throws DataException {
1239
        LOG.debug("finish editing of mode: {}", new Integer(mode));
1240
        try {
1241

    
1242
            /*
1243
             * Selection needs to be cleared when editing stops
1244
             * to prevent conflicts with selection remaining from
1245
             * editing mode.
1246
             */
1247
//            ((FeatureSelection) this.getSelection()).deselectAll();
1248

    
1249
            switch (mode) {
1250
            case MODE_QUERY:
1251
                throw new NeedEditingModeException(this.getName());
1252

    
1253
            case MODE_APPEND:
1254
                ((FeatureSelection) this.getSelection()).deselectAll();
1255
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1256
                provider.endAppend();
1257
                exitEditingMode();
1258
                updateIndexes();
1259
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1260
                break;
1261

    
1262
            case MODE_FULLEDIT:
1263
                if (hasStrongChanges && !this.allowWrite()) {
1264
                    throw new WriteNotAllowedException(getName());
1265
                }
1266

    
1267
                if(featureManager.isSelectionCompromised()) {
1268
                    ((FeatureSelection) this.getSelection()).deselectAll();
1269
                };
1270

    
1271
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1272
                if (hasStrongChanges) {
1273
                    validateFeatures(Feature.FINISH_EDITING);
1274

    
1275
                    /*
1276
                     * This will throw a PerformEditingExceptionif the provider
1277
                     * does not accept the changes (for example, an invalid field name)
1278
                     */
1279
                    provider.performChanges(featureManager.getDeleted(),
1280
                        featureManager.getInserted(),
1281
                        featureManager.getUpdated(),
1282
                        featureTypeManager.getFeatureTypesChanged());
1283
                }
1284
                exitEditingMode();
1285
                updateIndexes();
1286
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1287
                break;
1288
            }
1289
        } catch (PerformEditingException pee) {
1290
            throw new WriteException(provider.getSourceId().toString(), pee);
1291
        } catch (Exception e) {
1292
            throw new FinishEditingException(e);
1293
        }
1294
    }
1295

    
1296
    /**
1297
     * Save changes in the provider without leaving the edit mode.
1298
     * Do not call observers to communicate a change of ediding mode.
1299
     * The operation's history is eliminated to prevent inconsistencies
1300
     * in the data.
1301
     *
1302
     * @throws DataException
1303
     */
1304
    synchronized public void commitChanges() throws DataException {
1305
      LOG.debug("commitChanges of mode: {}", new Integer(mode));
1306
      if( !canCommitChanges() ) {
1307
              throw new WriteNotAllowedException(getName());
1308
      }
1309
      try {
1310
        switch (mode) {
1311
        case MODE_QUERY:
1312
          throw new NeedEditingModeException(this.getName());
1313

    
1314
        case MODE_APPEND:
1315
          this.provider.endAppend();
1316
          exitEditingMode();
1317
          invalidateIndexes();
1318
          this.provider.beginAppend();
1319
          hasInserts = false;
1320
          break;
1321

    
1322
        case MODE_FULLEDIT:
1323
          if (hasStrongChanges && !this.allowWrite()) {
1324
            throw new WriteNotAllowedException(getName());
1325
          }
1326
          if (hasStrongChanges) {
1327
            validateFeatures(Feature.FINISH_EDITING);
1328
            provider.performChanges(featureManager.getDeleted(),
1329
              featureManager.getInserted(),
1330
              featureManager.getUpdated(),
1331
              featureTypeManager.getFeatureTypesChanged());
1332
          }
1333
          invalidateIndexes();
1334
          featureManager =
1335
            new FeatureManager(new MemoryExpansionAdapter());
1336
          featureTypeManager =
1337
            new FeatureTypeManager(this, new MemoryExpansionAdapter());
1338
          spatialManager =
1339
            new SpatialManager(this, provider.getEnvelope());
1340

    
1341
          commands =
1342
            new DefaultFeatureCommandsStack(this, featureManager,
1343
              spatialManager, featureTypeManager);
1344
          featureCount = null;
1345
          hasStrongChanges = false;
1346
          hasInserts = false;
1347
          break;
1348
        }
1349
      } catch (Exception e) {
1350
        throw new FinishEditingException(e);
1351
      }
1352
    }
1353

    
1354
    synchronized public boolean canCommitChanges() throws DataException {
1355
        if ( !this.allowWrite()) {
1356
                return false;
1357
        }
1358
            switch (mode) {
1359
            default:
1360
        case MODE_QUERY:
1361
                return false;
1362

    
1363
        case MODE_APPEND:
1364
                return true;
1365

    
1366
        case MODE_FULLEDIT:
1367
            List types = this.getFeatureTypes();
1368
            for( int i=0; i<types.size(); i++ ) {
1369
                    Object type = types.get(i);
1370
                    if( type instanceof DefaultEditableFeatureType ) {
1371
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1372
                                    return false;
1373
                            }
1374
                    }
1375
            }
1376
            return true;
1377
            }
1378
    }
1379

    
1380
    public void beginEditingGroup(String description)
1381
        throws NeedEditingModeException {
1382
        checkInEditingMode();
1383
        commands.startComplex(description);
1384
    }
1385

    
1386
    public void endEditingGroup() throws NeedEditingModeException {
1387
        checkInEditingMode();
1388
        commands.endComplex();
1389
    }
1390

    
1391
    public boolean isAppendModeSupported() {
1392
        return this.provider.supportsAppendMode();
1393
    }
1394

    
1395
    public void export(DataServerExplorer explorer, String provider,
1396
        NewFeatureStoreParameters params) throws DataException {
1397

    
1398
        if (this.getFeatureTypes().size() != 1) {
1399
            throw new NotYetImplemented(
1400
                "export whith more than one type not yet implemented");
1401
        }
1402
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1403
        FeatureStore target = null;
1404
        FeatureSet features = null;
1405
        DisposableIterator iterator = null;
1406
        try {
1407
            FeatureType type = this.getDefaultFeatureType();
1408
            if ((params.getDefaultFeatureType() == null)
1409
                || (params.getDefaultFeatureType().size() == 0)) {
1410
                params.setDefaultFeatureType(type.getEditable());
1411

    
1412
            }
1413
            explorer.add(provider, params, true);
1414

    
1415
            DataManager manager = DALLocator.getDataManager();
1416
            target = (FeatureStore) manager.openStore(provider, params);
1417
            FeatureType targetType = target.getDefaultFeatureType();
1418

    
1419
            target.edit(MODE_APPEND);
1420
            FeatureAttributeDescriptor[] pk = type.getPrimaryKey();
1421
            if (featureSelection.getSize() > 0) {
1422
                features = this.getFeatureSelection();
1423
            } else {
1424
                if ((pk != null) && (pk.length > 0)) {
1425
                    FeatureQuery query = createFeatureQuery();
1426
                    for (int i = 0; i < pk.length; i++) {
1427
                        query.getOrder().add(pk[i].getName(), true);
1428
                    }
1429
                    features = this.getFeatureSet(query);
1430
                } else {
1431
                    features = this.getFeatureSet();
1432
                }
1433
            }
1434
            iterator = features.fastIterator();
1435
            while (iterator.hasNext()) {
1436
                DefaultFeature feature = (DefaultFeature) iterator.next();
1437
                target.insert(target.createNewFeature(targetType, feature));
1438
            }
1439
            target.finishEditing();
1440
            target.dispose();
1441
        } catch (Exception e) {
1442
            throw new DataExportException(e, params.toString());
1443
        } finally {
1444
            dispose(iterator);
1445
            dispose(features);
1446
            dispose(target);
1447
        }
1448
    }
1449

    
1450
    //
1451
    // ====================================================================
1452
    // Obtencion de datos
1453
    // getDataCollection, getFeatureCollection
1454
    //
1455

    
1456
    public DataSet getDataSet() throws DataException {
1457
        checkNotInAppendMode();
1458
        FeatureQuery query =
1459
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1460
        return new DefaultFeatureSet(this, query);
1461
    }
1462

    
1463
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1464
        checkNotInAppendMode();
1465
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1466
    }
1467

    
1468
    public void getDataSet(Observer observer) throws DataException {
1469
        checkNotInAppendMode();
1470
        this.getFeatureSet(null, observer);
1471
    }
1472

    
1473
    public void getDataSet(DataQuery dataQuery, Observer observer)
1474
        throws DataException {
1475
        checkNotInAppendMode();
1476
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1477
    }
1478

    
1479
    @Override
1480
    public FeatureSet getFeatureSet() throws DataException {
1481
        return this.getFeatureSet((FeatureQuery)null);
1482
    }
1483

    
1484
    @Override
1485
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1486
        throws DataException {
1487
        checkNotInAppendMode();
1488
        if( featureQuery==null ) {
1489
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1490
        }
1491
        return new DefaultFeatureSet(this, featureQuery);
1492
    }
1493

    
1494
    @Override
1495
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
1496
        try {
1497
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
1498
            return pager.asList();
1499
        } catch (BaseException ex) {
1500
            throw new RuntimeException("Can't create the list of features.", ex);
1501
        }
1502
    }
1503

    
1504
    @Override
1505
    public List<Feature> getFeatures() {
1506
        return this.getFeatures(null, 500);
1507
    }
1508

    
1509
    public void accept(Visitor visitor) throws BaseException {
1510
        FeatureSet set = getFeatureSet();
1511
        try {
1512
            set.accept(visitor);
1513
        } finally {
1514
            set.dispose();
1515
        }
1516
    }
1517

    
1518
    public void accept(Visitor visitor, DataQuery dataQuery)
1519
        throws BaseException {
1520
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
1521
        try {
1522
            set.accept(visitor);
1523
        } finally {
1524
            set.dispose();
1525
        }
1526
    }
1527

    
1528
    public FeatureType getFeatureType(FeatureQuery featureQuery)
1529
        throws DataException {
1530
        DefaultFeatureType fType =
1531
            (DefaultFeatureType) this.getFeatureType(featureQuery
1532
                .getFeatureTypeId());
1533
        if( featureQuery.hasAttributeNames() || featureQuery.hasConstantsAttributeNames() ) {
1534
            return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames() );
1535
        }
1536
        return fType;
1537
    }
1538

    
1539
    public void getFeatureSet(Observer observer) throws DataException {
1540
        checkNotInAppendMode();
1541
        this.getFeatureSet(null, observer);
1542
    }
1543

    
1544
    public void getFeatureSet(FeatureQuery query, Observer observer)
1545
        throws DataException {
1546
        class LoadInBackGround implements Runnable {
1547

    
1548
            private FeatureStore store;
1549
            private FeatureQuery query;
1550
            private Observer observer;
1551

    
1552
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
1553
                Observer observer) {
1554
                this.store = store;
1555
                this.query = query;
1556
                this.observer = observer;
1557
            }
1558

    
1559
            void notify(FeatureStoreNotification theNotification) {
1560
                observer.update(store, theNotification);
1561
                return;
1562
            }
1563

    
1564
            public void run() {
1565
                FeatureSet set = null;
1566
                try {
1567
                    set = store.getFeatureSet(query);
1568
                    notify(new DefaultFeatureStoreNotification(store,
1569
                        FeatureStoreNotification.LOAD_FINISHED, set));
1570
                } catch (Exception e) {
1571
                    notify(new DefaultFeatureStoreNotification(store,
1572
                        FeatureStoreNotification.LOAD_FINISHED, e));
1573
                } finally {
1574
                    dispose(set);
1575
                }
1576
            }
1577
        }
1578

    
1579
        checkNotInAppendMode();
1580
        if (query == null) {
1581
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
1582
        }
1583
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
1584
        Thread thread = new Thread(task, "Load Feature Set in background");
1585
        thread.start();
1586
    }
1587

    
1588
    public Feature getFeatureByReference(FeatureReference reference)
1589
        throws DataException {
1590
        checkNotInAppendMode();
1591
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
1592
        FeatureType featureType;
1593
        if (ref.getFeatureTypeId() == null) {
1594
            featureType = this.getDefaultFeatureType();
1595
        } else {
1596
            featureType = this.getFeatureType(ref.getFeatureTypeId());
1597
        }
1598
        return this.getFeatureByReference(reference, featureType);
1599
    }
1600

    
1601
    public Feature getFeatureByReference(FeatureReference reference,
1602
        FeatureType featureType) throws DataException {
1603
        checkNotInAppendMode();
1604
        featureType = fixFeatureType((DefaultFeatureType) featureType);
1605
        if (this.mode == MODE_FULLEDIT) {
1606
            Feature f = featureManager.get(reference, this, featureType);
1607
            if (f != null) {
1608
                return f;
1609
            }
1610
        }
1611

    
1612
        FeatureType sourceFeatureType = featureType;
1613
        if (!this.transforms.isEmpty()) {
1614
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
1615
        }
1616
        // TODO comprobar que el id es de este store
1617

    
1618
        DefaultFeature feature =
1619
            new DefaultFeature(this,
1620
                this.provider.getFeatureProviderByReference(
1621
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
1622

    
1623
        if (!this.transforms.isEmpty()) {
1624
            return this.transforms.applyTransform(feature, featureType);
1625
        }
1626
        return feature;
1627
    }
1628

    
1629
    //
1630
    // ====================================================================
1631
    // Gestion de features
1632
    //
1633

    
1634
    private FeatureType fixFeatureType(DefaultFeatureType type)
1635
        throws DataException {
1636
        FeatureType original = this.getDefaultFeatureType();
1637

    
1638
        if ((type == null) || type.equals(original)) {
1639
            return original;
1640
        } else {
1641
            if (!type.isSubtypeOf(original)) {
1642
                Iterator iter = this.getFeatureTypes().iterator();
1643
                FeatureType tmpType;
1644
                boolean found = false;
1645
                while (iter.hasNext()) {
1646
                    tmpType = (FeatureType) iter.next();
1647
                    if (type.equals(tmpType)) {
1648
                        return type;
1649

    
1650
                    } else
1651
                        if (type.isSubtypeOf(tmpType)) {
1652
                            found = true;
1653
                            original = tmpType;
1654
                            break;
1655
                        }
1656

    
1657
                }
1658
                if (!found) {
1659
                    throw new IllegalFeatureTypeException(getName());
1660
                }
1661
            }
1662
        }
1663

    
1664
        // Checks that type has all fields of pk
1665
        // else add the missing attributes at the end.
1666
        if (!original.hasOID()) {
1667
            // Gets original pk attributes
1668
            DefaultEditableFeatureType edOriginal =
1669
                (DefaultEditableFeatureType) original.getEditable();
1670
            FeatureAttributeDescriptor orgAttr;
1671
            Iterator edOriginalIter = edOriginal.iterator();
1672
            while (edOriginalIter.hasNext()) {
1673
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1674
                if (!orgAttr.isPrimaryKey()) {
1675
                    edOriginalIter.remove();
1676
                }
1677
            }
1678

    
1679
            // Checks if all pk attributes are in type
1680
            Iterator typeIterator;
1681
            edOriginalIter = edOriginal.iterator();
1682
            FeatureAttributeDescriptor attr;
1683
            while (edOriginalIter.hasNext()) {
1684
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1685
                typeIterator = type.iterator();
1686
                while (typeIterator.hasNext()) {
1687
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
1688
                    if (attr.getName().equals(orgAttr.getName())) {
1689
                        edOriginalIter.remove();
1690
                        break;
1691
                    }
1692
                }
1693
            }
1694

    
1695
            // add missing pk attributes if any
1696
            if (edOriginal.size() > 0) {
1697
                boolean isEditable = type instanceof DefaultEditableFeatureType;
1698
                DefaultEditableFeatureType edType =
1699
                    (DefaultEditableFeatureType) original.getEditable();
1700
                edType.clear();
1701
                edType.addAll(type);
1702
                edType.addAll(edOriginal);
1703
                if (!isEditable) {
1704
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
1705
                }
1706
            }
1707

    
1708
        }
1709

    
1710
        return type;
1711
    }
1712

    
1713
    public void validateFeatures(int mode) throws DataException {
1714
        FeatureSet collection = null;
1715
        DisposableIterator iter = null;
1716
        try {
1717
            checkNotInAppendMode();
1718
            collection = this.getFeatureSet();
1719
            iter = collection.fastIterator();
1720
            long previousVersionOfUpdate = currentVersionOfUpdate();
1721
            while (iter.hasNext()) {
1722
                ((DefaultFeature) iter.next()).validate(mode);
1723
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
1724
                    throw new ConcurrentDataModificationException(getName());
1725
                }
1726
            }
1727
        } catch (Exception e) {
1728
            throw new ValidateFeaturesException(e, getName());
1729
        } finally {
1730
            dispose(iter);
1731
            dispose(collection);
1732
        }
1733
    }
1734

    
1735
    public FeatureType getDefaultFeatureType() throws DataException {
1736
        try {
1737

    
1738
            if (isEditing()) {
1739
                FeatureType auxFeatureType =
1740
                    featureTypeManager.getType(defaultFeatureType.getId());
1741
                if (auxFeatureType != null) {
1742
                    return avoidEditable(auxFeatureType);
1743
                }
1744
            }
1745
            FeatureType type = this.transforms.getDefaultFeatureType();
1746
            if (type != null) {
1747
                return avoidEditable(type);
1748
            }
1749

    
1750
            return avoidEditable(defaultFeatureType);
1751

    
1752
        } catch (Exception e) {
1753
            throw new GetFeatureTypeException(e, getName());
1754
        }
1755
    }
1756

    
1757
    private FeatureType avoidEditable(FeatureType ft) {
1758
        if (ft instanceof EditableFeatureType) {
1759
            return ((EditableFeatureType) ft).getNotEditableCopy();
1760
        } else {
1761
            return ft;
1762
        }
1763
    }
1764

    
1765
    public FeatureType getFeatureType(String featureTypeId)
1766
        throws DataException {
1767
        if (featureTypeId == null) {
1768
            return this.getDefaultFeatureType();
1769
        }
1770
        try {
1771
            if (isEditing()) {
1772
                FeatureType auxFeatureType =
1773
                    featureTypeManager.getType(featureTypeId);
1774
                if (auxFeatureType != null) {
1775
                    return auxFeatureType;
1776
                }
1777
            }
1778
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
1779
            if (type != null) {
1780
                return type;
1781
            }
1782
            Iterator iter = this.featureTypes.iterator();
1783
            while (iter.hasNext()) {
1784
                type = (FeatureType) iter.next();
1785
                if (type.getId().equals(featureTypeId)) {
1786
                    return type;
1787
                }
1788
            }
1789
            return null;
1790
        } catch (Exception e) {
1791
            throw new GetFeatureTypeException(e, getName());
1792
        }
1793
    }
1794

    
1795
    public FeatureType getProviderDefaultFeatureType() {
1796
        return defaultFeatureType;
1797
    }
1798

    
1799
    public List getFeatureTypes() throws DataException {
1800
        try {
1801
            List types;
1802
            if (isEditing()) {
1803
                types = new ArrayList();
1804
                Iterator it = featureTypes.iterator();
1805
                while (it.hasNext()) {
1806
                    FeatureType type = (FeatureType) it.next();
1807
                    FeatureType typeaux =
1808
                        featureTypeManager.getType(type.getId());
1809
                    if (typeaux != null) {
1810
                        types.add(typeaux);
1811
                    } else {
1812
                        types.add(type);
1813
                    }
1814
                }
1815
                it = featureTypeManager.newsIterator();
1816
                while (it.hasNext()) {
1817
                    FeatureType type = (FeatureType) it.next();
1818
                    types.add(type);
1819
                }
1820
            } else {
1821
                types = this.transforms.getFeatureTypes();
1822
                if (types == null) {
1823
                    types = featureTypes;
1824
                }
1825
            }
1826
            return Collections.unmodifiableList(types);
1827
        } catch (Exception e) {
1828
            throw new GetFeatureTypeException(e, getName());
1829
        }
1830
    }
1831

    
1832
    public List getProviderFeatureTypes() throws DataException {
1833
        return Collections.unmodifiableList(this.featureTypes);
1834
    }
1835

    
1836
    public Feature createFeature(FeatureProvider data) throws DataException {
1837
        DefaultFeature feature = new DefaultFeature(this, data);
1838
        return feature;
1839
    }
1840

    
1841
    public Feature createFeature(FeatureProvider data, FeatureType type)
1842
        throws DataException {
1843
        // FIXME: falta por implementar
1844
        // Comprobar si es un subtipo del feature de data
1845
        // y construir un feature usando el subtipo.
1846
        // Probablemente requiera generar una copia del data.
1847
        throw new NotYetImplemented();
1848
    }
1849

    
1850
    public EditableFeature createNewFeature(FeatureType type,
1851
        Feature defaultValues) throws DataException {
1852
        try {
1853
            FeatureProvider data = createNewFeatureProvider(type);
1854
            DefaultEditableFeature feature =
1855
                new DefaultEditableFeature(this, data);
1856
            feature.initializeValues(defaultValues);
1857
            data.setNew(true);
1858

    
1859
            return feature;
1860
        } catch (Exception e) {
1861
            throw new CreateFeatureException(e, getName());
1862
        }
1863
    }
1864

    
1865
    private FeatureProvider createNewFeatureProvider(FeatureType type)
1866
        throws DataException {
1867
        type = this.fixFeatureType((DefaultFeatureType) type);
1868
        FeatureProvider data = this.provider.createFeatureProvider(type);
1869
        data.setNew(true);
1870
        if (type.hasOID() && (data.getOID() == null)) {
1871
            data.setOID(this.provider.createNewOID());
1872
        } else {
1873
            data.setOID(this.getTemporalOID());
1874
        }
1875
        return data;
1876

    
1877
    }
1878

    
1879
    public EditableFeature createNewFeature(FeatureType type,
1880
        boolean defaultValues) throws DataException {
1881
        try {
1882
            FeatureProvider data = createNewFeatureProvider(type);
1883
            DefaultEditableFeature feature =
1884
                new DefaultEditableFeature(this, data);
1885
            if (defaultValues) {
1886
                feature.initializeValues();
1887
            }
1888
            return feature;
1889
        } catch (Exception e) {
1890
            throw new CreateFeatureException(e, getName());
1891
        }
1892
    }
1893

    
1894
    public EditableFeature createNewFeature(boolean defaultValues)
1895
        throws DataException {
1896
        return this.createNewFeature(this.getDefaultFeatureType(),
1897
            defaultValues);
1898
    }
1899

    
1900
    public EditableFeature createNewFeature() throws DataException {
1901
        return this.createNewFeature(this.getDefaultFeatureType(), true);
1902
    }
1903

    
1904
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
1905
        FeatureType ft = this.getDefaultFeatureType();
1906
        EditableFeature f = this.createNewFeature(ft, false);
1907
        Iterator it = ft.iterator();
1908
        while(it.hasNext()) {
1909
            FeatureAttributeDescriptor desc = (FeatureAttributeDescriptor) it.next();
1910
            try {
1911
                f.set(desc.getName(), defaultValues.get(desc.getName()));
1912
            } catch(Throwable th) {
1913
                // Ignore
1914
            }
1915
        }
1916
        return f;
1917
    }
1918

    
1919
    public EditableFeatureType createFeatureType() {
1920
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType();
1921
        return ftype;
1922
    }
1923

    
1924
    public EditableFeatureType createFeatureType(String id) {
1925
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(id);
1926
        return ftype;
1927
    }
1928

    
1929
    //
1930
    // ====================================================================
1931
    // Index related methods
1932
    //
1933

    
1934
    public FeatureIndexes getIndexes() {
1935
        return this.indexes;
1936
    }
1937

    
1938
    public FeatureIndex createIndex(FeatureType featureType,
1939
        String attributeName, String indexName) throws DataException {
1940
        return createIndex(null, featureType, attributeName, indexName);
1941
    }
1942

    
1943
    public FeatureIndex createIndex(String indexTypeName,
1944
        FeatureType featureType, String attributeName, String indexName)
1945
        throws DataException {
1946

    
1947
        return createIndex(indexTypeName, featureType, attributeName,
1948
            indexName, false, null);
1949
    }
1950

    
1951
    public FeatureIndex createIndex(FeatureType featureType,
1952
        String attributeName, String indexName, Observer observer)
1953
        throws DataException {
1954
        return createIndex(null, featureType, attributeName, indexName,
1955
            observer);
1956
    }
1957

    
1958
    public FeatureIndex createIndex(String indexTypeName,
1959
        FeatureType featureType, String attributeName, String indexName,
1960
        final Observer observer) throws DataException {
1961

    
1962
        return createIndex(indexTypeName, featureType, attributeName,
1963
            indexName, true, observer);
1964
    }
1965

    
1966
    private FeatureIndex createIndex(String indexTypeName,
1967
        FeatureType featureType, String attributeName, String indexName,
1968
        boolean background, final Observer observer) throws DataException {
1969

    
1970
        checkNotInAppendMode();
1971
        FeatureIndexProviderServices index = null;
1972
        index =
1973
            dataManager.createFeatureIndexProvider(indexTypeName, this,
1974
                featureType, indexName,
1975
                featureType.getAttributeDescriptor(attributeName));
1976

    
1977
        try {
1978
            index.fill(background, observer);
1979
        } catch (FeatureIndexException e) {
1980
            throw new InitializeException(index.getName(), e);
1981
        }
1982

    
1983
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
1984
        return index;
1985
    }
1986

    
1987
    //
1988
    // ====================================================================
1989
    // Transforms related methods
1990
    //
1991

    
1992
    public FeatureStoreTransforms getTransforms() {
1993
        return this.transforms;
1994
    }
1995

    
1996
    public FeatureQuery createFeatureQuery() {
1997
        return new DefaultFeatureQuery();
1998
    }
1999

    
2000
    public DataQuery createQuery() {
2001
        return createFeatureQuery();
2002
    }
2003

    
2004
    //
2005
    // ====================================================================
2006
    // UndoRedo related methods
2007
    //
2008

    
2009
    public boolean canRedo() {
2010
        return commands.canRedo();
2011
    }
2012

    
2013
    public boolean canUndo() {
2014
        return commands.canUndo();
2015
    }
2016

    
2017
    public void redo(int num) throws RedoException {
2018
        for (int i = 0; i < num; i++) {
2019
            redo();
2020
        }
2021
    }
2022

    
2023
    public void undo(int num) throws UndoException {
2024
        for (int i = 0; i < num; i++) {
2025
            undo();
2026
        }
2027
    }
2028

    
2029
    //
2030
    // ====================================================================
2031
    // Metadata related methods
2032
    //
2033

    
2034
    public Object getMetadataID() {
2035
        return this.provider.getSourceId();
2036
    }
2037

    
2038
    public void delegate(DynObject dynObject) {
2039
        this.metadata.delegate(dynObject);
2040
    }
2041

    
2042
    public DynClass getDynClass() {
2043
        return this.metadata.getDynClass();
2044
    }
2045

    
2046
        public Object getDynValue(String name) throws DynFieldNotFoundException {
2047
                if( this.transforms.hasDynValue(name) ) {
2048
                        return this.transforms.getDynValue(name);
2049
                }
2050
                if (this.metadata.hasDynValue(name)) {
2051
                        return this.metadata.getDynValue(name);
2052
                }
2053
                if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2054
                        return this.provider.getProviderName();
2055
                } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2056
                        return this.provider.getSourceId();
2057
                } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2058
                        try {
2059
                                return this.getDefaultFeatureType();
2060
                        } catch (DataException e) {
2061
                                return null;
2062
                        }
2063
                }
2064
                return this.metadata.getDynValue(name);
2065
        }
2066

    
2067
    public boolean hasDynValue(String name) {
2068
                if( this.transforms.hasDynValue(name) ) {
2069
                        return true;
2070
                }
2071
        return this.metadata.hasDynValue(name);
2072
    }
2073

    
2074
    public void implement(DynClass dynClass) {
2075
        this.metadata.implement(dynClass);
2076
    }
2077

    
2078
    public Object invokeDynMethod(String name, Object[] args)
2079
        throws DynMethodException {
2080
        return this.metadata.invokeDynMethod(this, name, args);
2081
    }
2082

    
2083
    public Object invokeDynMethod(int code, Object[] args)
2084
        throws DynMethodException {
2085
        return this.metadata.invokeDynMethod(this, code, args);
2086
    }
2087

    
2088
    public void setDynValue(String name, Object value)
2089
        throws DynFieldNotFoundException {
2090
                if( this.transforms.hasDynValue(name) ) {
2091
                        this.transforms.setDynValue(name, value);
2092
                        return;
2093
                }
2094
        this.metadata.setDynValue(name, value);
2095

    
2096
    }
2097

    
2098
    /*
2099
     * (non-Javadoc)
2100
     *
2101
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2102
     */
2103
    public Set getMetadataChildren() {
2104
        return this.metadataChildren;
2105
    }
2106

    
2107
    /*
2108
     * (non-Javadoc)
2109
     *
2110
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2111
     */
2112
    public String getMetadataName() {
2113
        return this.provider.getProviderName();
2114
    }
2115

    
2116
    public FeatureTypeManager getFeatureTypeManager() {
2117
        return this.featureTypeManager;
2118
    }
2119

    
2120
    public long getFeatureCount() throws DataException {
2121
        if (featureCount == null) {
2122
            featureCount = new Long(this.provider.getFeatureCount());
2123
        }
2124
        if (this.isEditing()) {
2125
            if(this.isAppending()) {
2126
                try{
2127
                    throw new IllegalStateException();
2128
                } catch(IllegalStateException e) {
2129
                    LOG.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND");
2130
                    e.printStackTrace();
2131
                }
2132
                return -1;
2133
            } else {
2134
                return featureCount.longValue()
2135
                    + this.featureManager.getDeltaSize();
2136
            }
2137
        }
2138
        return featureCount.longValue();
2139
    }
2140

    
2141
    private Long getTemporalOID() {
2142
        return new Long(this.temporalOid++);
2143
    }
2144

    
2145
    public FeatureType getProviderFeatureType(String featureTypeId) {
2146
        if (featureTypeId == null) {
2147
            return this.defaultFeatureType;
2148
        }
2149
        FeatureType type;
2150
        Iterator iter = this.featureTypes.iterator();
2151
        while (iter.hasNext()) {
2152
            type = (FeatureType) iter.next();
2153
            if (type.getId().equals(featureTypeId)) {
2154
                return type;
2155
            }
2156
        }
2157
        return null;
2158
    }
2159

    
2160
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2161
        return ((DefaultFeature) feature).getData();
2162
    }
2163

    
2164
    public DataStore getStore() {
2165
        return this;
2166
    }
2167

    
2168
    public FeatureStore getFeatureStore() {
2169
        return this;
2170
    }
2171

    
2172
    public void createCache(String name, DynObject parameters)
2173
        throws DataException {
2174
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2175
        if (cache == null) {
2176
            throw new CreateException("FeaureCacheProvider", null);
2177
        }
2178
        cache.apply(this, provider);
2179
        provider = cache;
2180

    
2181
        featureCount = null;
2182
    }
2183

    
2184
    public FeatureCache getCache() {
2185
        return cache;
2186
    }
2187

    
2188
    public void clear() {
2189
        if (metadata != null) {
2190
            metadata.clear();
2191
        }
2192
    }
2193

    
2194
    public String getName() {
2195
        return this.provider.getName();
2196
    }
2197

    
2198
    public String getFullName() {
2199
        try {
2200
            return this.provider.getFullName();
2201
        } catch(Throwable th) {
2202
            return null;
2203
        }
2204
    }
2205

    
2206
    public String getProviderName() {
2207
        return this.provider.getProviderName();
2208
    }
2209

    
2210
    public boolean isKnownEnvelope() {
2211
        return this.provider.isKnownEnvelope();
2212
    }
2213

    
2214
    public boolean hasRetrievedFeaturesLimit() {
2215
        return this.provider.hasRetrievedFeaturesLimit();
2216
    }
2217

    
2218
    public int getRetrievedFeaturesLimit() {
2219
        return this.provider.getRetrievedFeaturesLimit();
2220
    }
2221

    
2222
    public Interval getInterval() {
2223
        if( this.timeSupport!=null ) {
2224
            return this.timeSupport.getInterval();
2225
        }
2226
        return this.provider.getInterval();
2227
    }
2228

    
2229
    public Collection getTimes() {
2230
        if( this.timeSupport!=null ) {
2231
            return this.timeSupport.getTimes();
2232
        }
2233
        return this.provider.getTimes();
2234
    }
2235

    
2236
    public Collection getTimes(Interval interval) {
2237
        if( this.timeSupport!=null ) {
2238
            return this.timeSupport.getTimes(interval);
2239
        }
2240
        return this.provider.getTimes(interval);
2241
    }
2242

    
2243
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
2244
        FeatureAttributeDescriptor attr;
2245
        DefaultFeatureType ft;
2246
        try {
2247
            ft = (DefaultFeatureType) this.getDefaultFeatureType();
2248
        } catch (DataException ex) {
2249
            throw new RuntimeException("Can't add time support, can't get the default feature type.", ex);
2250
        }
2251
        attr = ft.getAttributeDescriptor(timeSupport.getAttributeName());
2252
        if( attr != null ) {
2253
            throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
2254
        }
2255
        attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
2256
        if( attr != null ) {
2257
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
2258
        }
2259
        DefaultEditableFeatureAttributeDescriptor attr2 = new DefaultEditableFeatureAttributeDescriptor();
2260
        attr2.setDataType(timeSupport.getDataType());
2261
        attr2.setIsTime(true);
2262
        attr2.setFeatureAttributeEmulator(timeSupport);
2263
        ft.add(attr2);
2264

    
2265
        this.timeSupport = timeSupport;
2266
    }
2267

    
2268
    /* (non-Javadoc)
2269
     * @see java.lang.Object#clone()
2270
     */
2271
    public Object clone() throws CloneNotSupportedException {
2272

    
2273
        DataStoreParameters dsp = getParameters();
2274

    
2275
        DefaultFeatureStore cloned_store = null;
2276

    
2277
        try {
2278
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2279
                openStore(this.getProviderName(), dsp);
2280
            if (transforms != null) {
2281
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2282
                cloned_store.transforms.setStoreForClone(cloned_store);
2283
            }
2284
        } catch (Exception e) {
2285
            throw new CloneException(e);
2286
        }
2287
        return cloned_store;
2288

    
2289
    }
2290

    
2291
    public Feature getFeature(DynObject dynobject) {
2292
        if (dynobject instanceof DynObjectFeatureFacade){
2293
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2294
            return f;
2295
        }
2296
        return null;
2297
    }
2298

    
2299
    public Iterator iterator() {
2300
        try {
2301
            return this.getFeatureSet().fastIterator();
2302
        } catch (DataException ex) {
2303
            throw new RuntimeException(ex);
2304
        }
2305
    }
2306

    
2307
    @Override
2308
    public ExpressionEvaluator createExpression() {
2309
        if( this.provider instanceof FeatureStoreProvider_v2 ) {
2310
            return ((FeatureStoreProvider_v2)this.provider).createExpression();
2311
        }
2312
        return new SQLBuilderBase();
2313
    }
2314

    
2315

    
2316
    public FeatureSet features() throws DataException {
2317
        // This is to avoid jython to create a property with this name
2318
        // to access method getFeatures.
2319
        return this.getFeatureSet();
2320
    }
2321

    
2322
    @Override
2323
    public DataStoreProviderFactory getFactory() {
2324
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
2325
        return factory;
2326
    }
2327

    
2328
    @Override
2329
    public void useCache(String providerName, DynObject parameters) throws DataException {
2330
        throw new UnsupportedOperationException();
2331
    }
2332
}