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

History | View | Annotate | Download (77.4 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
import java.util.ArrayList;
29
import java.util.Collection;
30
import java.util.Collections;
31
import java.util.HashMap;
32
import java.util.HashSet;
33
import java.util.Iterator;
34
import java.util.List;
35
import java.util.Map;
36
import java.util.Map.Entry;
37
import java.util.Set;
38

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

    
155
public class DefaultFeatureStore extends AbstractDisposable implements
156
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
157

    
158
    private static final Logger LOG = LoggerFactory
159
        .getLogger(DefaultFeatureStore.class);
160

    
161
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
162

    
163
    private DataStoreParameters parameters = null;
164
    private FeatureSelection selection;
165
    private FeatureLocks locks;
166

    
167
    private DelegateWeakReferencingObservable delegateObservable =
168
        new DelegateWeakReferencingObservable(this);
169

    
170
    private FeatureCommandsStack commands;
171
    private FeatureTypeManager featureTypeManager;
172
    private FeatureManager featureManager;
173
    private SpatialManager spatialManager;
174

    
175
    private FeatureType defaultFeatureType = null;
176
    private List featureTypes = new ArrayList();
177

    
178
    private int mode = MODE_QUERY;
179
    private long versionOfUpdate = 0;
180
    private boolean hasStrongChanges = true;
181
    private boolean hasInserts = true;
182

    
183
    private DefaultDataManager dataManager = null;
184

    
185
    private FeatureStoreProvider provider = null;
186

    
187
    private DefaultFeatureIndexes indexes;
188

    
189
    private DefaultFeatureStoreTransforms transforms;
190

    
191
    DelegatedDynObject metadata;
192

    
193
    private Set metadataChildren;
194

    
195
    private Long featureCount = null;
196

    
197
    private long temporalOid = 0;
198

    
199
    private FeatureCacheProvider cache;
200

    
201
    /*
202
     * TODO:
203
     *
204
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
205
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
206
     * featureType al que se le han cambiado las reglas de validacion cuando
207
     * hasStrongChanges=false.
208
     */
209

    
210
    public DefaultFeatureStore() {
211

    
212
    }
213

    
214
    @Override
215
    public void intialize(DataManager dataManager,
216
        DataStoreParameters parameters) throws InitializeException {
217

    
218
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
219

    
220
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
221
            FeatureStore.METADATA_DEFINITION_NAME, 
222
            MetadataManager.METADATA_NAMESPACE
223
        );
224

    
225
        this.dataManager = (DefaultDataManager) dataManager;
226

    
227
        this.parameters = parameters;
228
        this.transforms = new DefaultFeatureStoreTransforms(this);
229
        try {
230
            indexes = new DefaultFeatureIndexes(this);
231
        } catch (DataException e) {
232
            throw new InitializeException(e);
233
        }
234

    
235
    }
236

    
237
    @Override
238
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
239
        this.provider = (FeatureStoreProvider) provider;
240
        this.delegate((DynObject) provider);
241
        this.metadataChildren = new HashSet();
242
        this.metadataChildren.add(provider);
243
    }
244

    
245
    public DataStoreParameters getParameters() {
246
        return parameters;
247
    }
248

    
249
    public int getMode() {
250
        return this.mode;
251
    }
252

    
253
    public DataManager getManager() {
254
        return this.dataManager;
255
    }
256

    
257
    public Iterator getChildren() {
258
        return this.provider.getChilds();
259
    }
260

    
261
    public FeatureStoreProvider getProvider() {
262
        return this.provider;
263
    }
264

    
265
    public FeatureManager getFeatureManager() {
266
        return this.featureManager;
267
    }
268

    
269
    public void setFeatureTypes(List types, FeatureType defaultType) {
270
        this.featureTypes = types;
271
        this.defaultFeatureType = defaultType;
272
    }
273

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

    
288
    public void refresh() throws OpenException, InitializeException {
289
        if (this.mode != MODE_QUERY) {
290
            throw new IllegalStateException();
291
        }
292
        this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH);
293
        this.featureCount = null;
294
        this.provider.refresh();
295
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
296
    }
297

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

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

    
336
        if (this.featureTypeManager != null) {
337
            this.featureTypeManager.dispose();
338
            this.featureTypeManager = null;
339
        }
340

    
341
        this.featureManager = null;
342
        this.spatialManager = null;
343

    
344
        this.parameters = null;
345
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
346
        if (delegateObservable != null) {
347
            this.delegateObservable.deleteObservers();
348
            this.delegateObservable = null;
349
        }
350
    }
351

    
352
    public boolean allowWrite() {
353
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
354
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
355
            return false;
356
        }
357
        return this.provider.allowWrite();
358
    }
359

    
360
    public boolean canWriteGeometry(int geometryType) throws DataException {
361
        return this.provider.canWriteGeometry(geometryType, 0);
362
    }
363

    
364
    public DataServerExplorer getExplorer() throws ReadException,
365
        ValidateDataParametersException {
366
        return this.provider.getExplorer();
367
    }
368

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

    
381
    public Envelope getEnvelope() throws DataException {
382
        if (this.mode == MODE_FULLEDIT) {
383
                // Just in case another thread tries to write in the store
384
                synchronized (this) {
385
                        return this.spatialManager.getEnvelope();
386
                        }
387
        }
388
        if (hasDynValue(DataStore.METADATA_ENVELOPE)){
389
            return (Envelope)getDynValue(DataStore.METADATA_ENVELOPE);
390
        }
391
        return this.provider.getEnvelope();
392
    }
393

    
394
    /**
395
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
396
     */
397
    public IProjection getSRSDefaultGeometry() throws DataException {
398
        return this.getDefaultFeatureType().getDefaultSRS();
399
    }
400

    
401
    public FeatureSelection createDefaultFeatureSelection()
402
        throws DataException {
403
        return new DefaultFeatureSelection(this);
404
    }
405

    
406
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
407
        throws DataException {
408
        if (type.hasOID()) {
409
            return new DefaultFeatureProvider(type,
410
                this.provider.createNewOID());
411
        }
412
        return new DefaultFeatureProvider(type);
413
    }
414

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

    
449
        }
450

    
451
        if (evaluatedAttr.isEmpty()) {
452
            evaluatedAttr = null;
453
        }
454

    
455
        state.set("evaluatedAttributes", evaluatedAttr);
456
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
457

    
458
    }
459

    
460
    public void loadFromState(PersistentState state)
461
        throws PersistenceException {
462
        if (this.provider != null) {
463
            throw new PersistenceStoreAlreadyLoadedException(this.getName());
464
        }
465
        if (this.getManager() == null) {
466
            this.dataManager = (DefaultDataManager) DALLocator.getDataManager();
467
        }
468

    
469
        DataStoreParameters params =
470
            (DataStoreParameters) state.get("parameters");
471

    
472
        DataStoreProvider prov;
473
        try {
474
            this.intialize(this.dataManager, params);
475
            prov = this.dataManager.createProvider(
476
                    (DataStoreProviderServices) this, 
477
                    params
478
            );
479
            this.setProvider(prov);
480
            
481
            this.selection = (FeatureSelection) state.get("selection");
482
            this.transforms =
483
                (DefaultFeatureStoreTransforms) state.get("transforms");
484
            Map evaluatedAttributes = (Map) state.get("evaluatedAttributes");
485
            if ((evaluatedAttributes != null) && !evaluatedAttributes.isEmpty()) {
486
                List attrs;
487
                Iterator iterEntries =
488
                    evaluatedAttributes.entrySet().iterator();
489
                Entry entry;
490
                while (iterEntries.hasNext()) {
491
                    entry = (Entry) iterEntries.next();
492
                    attrs = (List) entry.getValue();
493
                    if (attrs.isEmpty()) {
494
                        continue;
495
                    }
496
                    int fTypePos = -1;
497
                    DefaultFeatureType type = null;
498
                    for (int i = 0; i < featureTypes.size(); i++) {
499
                        type = (DefaultFeatureType) featureTypes.get(i);
500
                        if (type.getId().equals(entry.getKey())) {
501
                            fTypePos = i;
502
                            break;
503
                        }
504
                    }
505
                    if (fTypePos < 0) {
506
                        throw new PersistenceCantFindFeatureTypeException(
507
                            this.getName(), (String) entry.getKey());
508
                    }
509
                    DefaultEditableFeatureType eType =
510
                        (DefaultEditableFeatureType) type.getEditable();
511
                    Iterator iterAttr = attrs.iterator();
512
                    FeatureAttributeDescriptor attr;
513
                    while (iterAttr.hasNext()) {
514
                        attr = (FeatureAttributeDescriptor) iterAttr.next();
515
                        eType.addLike(attr);
516
                    }
517
                    featureTypes.set(fTypePos, eType.getNotEditableCopy());
518

    
519
                }
520

    
521
            }
522

    
523
            String defFTypeid = state.getString("defaultFeatureTypeId");
524
            FeatureType ftype = null;
525

    
526
            if (this.defaultFeatureType == null ||
527
                this.defaultFeatureType.getId() == null ||
528
                !this.defaultFeatureType.getId().equals(
529
                state.getString("defaultFeatureTypeId"))) {
530

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

    
549
        } catch (InitializeException e) {
550
            throw new PersistenceException(e);
551
        } catch (DataException e) {
552
            throw new PersistenceException(e);
553
        }
554

    
555
    }
556

    
557
    public static void registerPersistenceDefinition() {
558
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
559
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
560
            DynStruct definition =
561
                manager.addDefinition(DefaultFeatureStore.class,
562
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
563
                        + " Persistent definition", null, null);
564
            definition.addDynFieldString("dataStoreName").setMandatory(true)
565
                .setPersistent(true);
566

    
567
            definition.addDynFieldObject("parameters")
568
                .setClassOfValue(DynObject.class).setMandatory(true)
569
                .setPersistent(true);
570

    
571
            definition.addDynFieldObject("selection")
572
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
573
                .setPersistent(true);
574

    
575
            definition.addDynFieldObject("transforms")
576
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
577
                .setMandatory(true).setPersistent(true);
578

    
579
            definition.addDynFieldMap("evaluatedAttributes")
580
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
581
                .setMandatory(false).setPersistent(true);
582

    
583
            definition.addDynFieldString("defaultFeatureTypeId")
584
                .setMandatory(true).setPersistent(true);
585
        }
586
    }
587

    
588
    public static void registerMetadataDefinition() throws MetadataException {
589
        MetadataManager manager = MetadataLocator.getMetadataManager();
590
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
591
            DynStruct metadataDefinition =
592
                manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
593
            metadataDefinition.extend(manager
594
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
595
        }
596
    }
597

    
598
    //
599
    // ====================================================================
600
    // Gestion de la seleccion
601
    //
602

    
603
    public void setSelection(DataSet selection) throws DataException {
604
        this.setSelection((FeatureSet) selection);
605
    }
606

    
607
    public DataSet createSelection() throws DataException {
608
        return createFeatureSelection();
609
    }
610

    
611
    public DataSet getSelection() throws DataException {
612
        return this.getFeatureSelection();
613
    }
614

    
615
    public void setSelection(FeatureSet selection) throws DataException {
616
        setSelection(selection, true);
617
    }
618

    
619
    /**
620
     * @see #setSelection(FeatureSet)
621
     * @param undoable
622
     *            if the action must be undoable
623
     */
624
    public void setSelection(FeatureSet selection, boolean undoable)
625
        throws DataException {
626
        if (selection == null) {
627
            if (undoable) {
628
                throw new SelectionNotAllowedException(getName());
629
            }
630

    
631
        } else {
632
            if (selection.equals(this.selection)) {
633
                return;
634
            }
635
            if (!selection.isFromStore(this)) {
636
                throw new SelectionNotAllowedException(getName());
637
            }
638
        }
639

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

    
678
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
679
    }
680

    
681
    public FeatureSelection createFeatureSelection() throws DataException {
682
        return this.provider.createFeatureSelection();
683
    }
684

    
685
    public FeatureSelection getFeatureSelection() throws DataException {
686
        if (selection == null) {
687
            this.selection = createFeatureSelection();
688
            this.selection.addObserver(this);
689
        }
690
        return selection;
691
    }
692

    
693
    //
694
    // ====================================================================
695
    // Gestion de notificaciones
696
    //
697

    
698
    public void notifyChange(String notification) {
699
        if (delegateObservable != null) {
700
            notifyChange(new DefaultFeatureStoreNotification(this, notification));
701
        }
702

    
703
    }
704

    
705
    public void notifyChange(String notification, FeatureProvider data) {
706
        try {
707
            notifyChange(notification, createFeature(data));
708
        } catch (DataException ex) {
709
            LOG.error("Error notifying about the notification: " + notification
710
                + ", with the data: " + data, ex);
711
        }
712
    }
713

    
714
    public void notifyChange(String notification, Feature feature) {
715
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
716
            feature));
717
    }
718

    
719
    public void notifyChange(String notification, Command command) {
720
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
721
            command));
722
    }
723

    
724
    public void notifyChange(String notification, EditableFeatureType type) {
725
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
726
            type));
727
    }
728

    
729
    public void notifyChange(FeatureStoreNotification storeNotification) {
730
        delegateObservable.notifyObservers(storeNotification);
731
    }
732

    
733
    public void notifyChange(String notification, Resource resource) {
734
        notifyChange(new DefaultFeatureStoreNotification(this,
735
            DataStoreNotification.RESOURCE_CHANGED));
736
    }
737

    
738
    //
739
    // ====================================================================
740
    // Gestion de bloqueos
741
    //
742

    
743
    public boolean isLocksSupported() {
744
        return this.provider.isLocksSupported();
745
    }
746

    
747
    public FeatureLocks getLocks() throws DataException {
748
        if (!this.provider.isLocksSupported()) {
749
            LOG.warn("Locks not supported");
750
            return null;
751
        }
752
        if (locks == null) {
753
            this.locks = this.provider.createFeatureLocks();
754
        }
755
        return locks;
756
    }
757

    
758
    //
759
    // ====================================================================
760
    // Interface Observable
761
    //
762

    
763
    public void disableNotifications() {
764
        this.delegateObservable.disableNotifications();
765

    
766
    }
767

    
768
    public void enableNotifications() {
769
        this.delegateObservable.enableNotifications();
770
    }
771

    
772
    public void beginComplexNotification() {
773
        this.delegateObservable.beginComplexNotification();
774

    
775
    }
776

    
777
    public void endComplexNotification() {
778
        this.delegateObservable.endComplexNotification();
779

    
780
    }
781

    
782
    public void addObserver(Observer observer) {
783
        if (delegateObservable != null) {
784
            this.delegateObservable.addObserver(observer);
785
        }
786
    }
787

    
788
    public void deleteObserver(Observer observer) {
789
        if (delegateObservable != null) {
790
            this.delegateObservable.deleteObserver(observer);
791
        }
792
    }
793

    
794
    public void deleteObservers() {
795
        this.delegateObservable.deleteObservers();
796

    
797
    }
798

    
799
    //
800
    // ====================================================================
801
    // Interface Observer
802
    //
803
    // Usado para observar:
804
    // - su seleccion
805
    // - sus bloqueos
806
    // - sus recursos
807
    //
808

    
809
    public void update(Observable observable, Object notification) {
810
        if (observable instanceof FeatureSet) {
811
            if (observable == this.selection) {
812
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
813
            } else
814
                if (observable == this.locks) {
815
                    this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
816
                }
817

    
818
        } else
819
            if (observable instanceof FeatureStoreProvider) {
820
                if (observable == this.provider) {
821

    
822
                }
823

    
824
            }
825
    }
826

    
827
    //
828
    // ====================================================================
829
    // Edicion
830
    //
831

    
832
    private void newVersionOfUpdate() {
833
        this.versionOfUpdate++;
834
    }
835

    
836
    private long currentVersionOfUpdate() {
837
        return this.versionOfUpdate;
838
    }
839

    
840
    private void checkInEditingMode() throws NeedEditingModeException {
841
        if (mode != MODE_FULLEDIT) {
842
            throw new NeedEditingModeException(this.getName());
843
        }
844
    }
845

    
846
    private void checkNotInAppendMode() throws IllegalStateException {
847
        if (mode == MODE_APPEND) {
848
                        throw new IllegalStateException("Error: store "
849
                                        + this.getFullName() + " is in append mode");
850
        }
851
    }
852

    
853
    private void checkIsOwnFeature(Feature feature)
854
        throws IllegalFeatureException {
855
        if (((DefaultFeature) feature).getStore() != this) {
856
            throw new IllegalFeatureException(this.getName());
857
        }
858
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
859
        // fixFeatureType((DefaultFeatureType) feature.getType());
860
    }
861

    
862
    private void exitEditingMode() {
863
        if (commands != null) {
864
            commands.clear();
865
            commands = null;
866
        }
867

    
868
        if (featureTypeManager != null) {
869
            featureTypeManager.dispose();
870
            featureTypeManager = null;
871

    
872
        }
873

    
874
        // TODO implementar un dispose para estos dos
875
        featureManager = null;
876
        spatialManager = null;
877

    
878
        featureCount = null;
879

    
880
        mode = MODE_QUERY;
881
        hasStrongChanges = true; // Lo deja a true por si las moscas
882
        hasInserts = true;
883
    }
884

    
885
    synchronized public void edit() throws DataException {
886
        edit(MODE_FULLEDIT);
887
    }
888

    
889
    synchronized public void edit(int mode) throws DataException {
890
        LOG.debug("Starting editing in mode: {}", new Integer(mode));
891
        try {
892
            if (this.mode != MODE_QUERY) {
893
                throw new AlreadyEditingException(this.getName());
894
            }
895
            if (!this.provider.supportsAppendMode()) {
896
                mode = MODE_FULLEDIT;
897
            }
898
            switch (mode) {
899
            case MODE_QUERY:
900
                throw new IllegalStateException(this.getName());
901

    
902
            case MODE_FULLEDIT:
903
                if (!this.transforms.isEmpty()) {
904
                    throw new IllegalStateException(this.getName());
905
                }
906
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
907
                invalidateIndexes();
908
                featureManager =
909
                    new FeatureManager(new MemoryExpansionAdapter());
910
                featureTypeManager =
911
                    new FeatureTypeManager(this, new MemoryExpansionAdapter());
912
                spatialManager =
913
                    new SpatialManager(this, provider.getEnvelope());
914

    
915
                commands =
916
                    new DefaultFeatureCommandsStack(this, featureManager,
917
                        spatialManager, featureTypeManager);
918
                this.mode = MODE_FULLEDIT;
919
                hasStrongChanges = false;
920
                hasInserts = false;
921
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
922
                break;
923
            case MODE_APPEND:
924
                if (!this.transforms.isEmpty()) {
925
                    throw new IllegalStateException(this.getName());
926
                }
927
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
928
                invalidateIndexes();
929
                this.provider.beginAppend();
930
                this.mode = MODE_APPEND;
931
                hasInserts = false;
932
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
933
                break;
934
            }
935
        } catch (Exception e) {
936
            throw new StoreEditException(e, this.getName());
937
        }
938
    }
939

    
940
    private void invalidateIndexes() {
941
        setIndexesValidStatus(false);
942
    }
943

    
944
    private void setIndexesValidStatus(boolean valid) {
945
        FeatureIndexes indexes = getIndexes();
946
        LOG.debug("Setting the store indexes to valid status {}: {}", (valid
947
            ? Boolean.TRUE : Boolean.FALSE), indexes);
948
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
949
            FeatureIndex index = (FeatureIndex) iterator.next();
950
            if (index instanceof FeatureIndexProviderServices) {
951
                FeatureIndexProviderServices indexServices =
952
                    (FeatureIndexProviderServices) index;
953
                indexServices.setValid(valid);
954
            }
955
        }
956
    }
957

    
958
    private void updateIndexes() throws FeatureIndexException {
959
        FeatureIndexes indexes = getIndexes();
960
        LOG.debug("Refilling indexes: {}", indexes);
961
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
962
            FeatureIndex index = (FeatureIndex) iterator.next();
963
            if (index instanceof FeatureIndexProviderServices) {
964
                FeatureIndexProviderServices indexServices =
965
                    (FeatureIndexProviderServices) index;
966
                indexServices.fill(true, null);
967
            }
968
        }
969
    }
970

    
971
    private void waitForIndexes() {
972
        FeatureIndexes indexes = getIndexes();
973
        LOG.debug("Waiting for indexes to finish filling: {}", indexes);
974
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
975
            FeatureIndex index = (FeatureIndex) iterator.next();
976
            if (index instanceof FeatureIndexProviderServices) {
977
                FeatureIndexProviderServices indexServices =
978
                    (FeatureIndexProviderServices) index;
979
                indexServices.waitForIndex();
980
            }
981
        }
982
    }
983

    
984
    private void disposeIndexes() {
985
        FeatureIndexes indexes = getIndexes();
986
        LOG.debug("Disposing indexes: {}", indexes);
987
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
988
            FeatureIndex index = (FeatureIndex) iterator.next();
989
            if (index instanceof FeatureIndexProviderServices) {
990
                FeatureIndexProviderServices indexServices =
991
                    (FeatureIndexProviderServices) index;
992
                indexServices.dispose();
993
            }
994
        }
995
    }
996

    
997
    public boolean isEditing() {
998
        return mode == MODE_FULLEDIT;
999
    }
1000

    
1001
    public boolean isAppending() {
1002
        return mode == MODE_APPEND;
1003
    }
1004

    
1005
    synchronized public void update(EditableFeatureType type)
1006
        throws DataException {
1007
        try {
1008
            checkInEditingMode();
1009
            if (type == null) {
1010
                throw new NullFeatureTypeException(getName());
1011
            }
1012
            // FIXME: Comprobar que es un featureType aceptable.
1013
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
1014
            newVersionOfUpdate();
1015

    
1016
            FeatureType oldt = type.getSource().getCopy();
1017
            FeatureType newt = type.getCopy();
1018
            commands.update(newt, oldt);
1019

    
1020
            if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
1021
                hasStrongChanges = true;
1022
            }
1023
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1024
        } catch (Exception e) {
1025
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1026
        }
1027
    }
1028

    
1029
    public void delete(Feature feature) throws DataException {
1030
        this.commands.delete(feature);
1031
    }
1032

    
1033
    synchronized public void doDelete(Feature feature) throws DataException {
1034
        try {
1035
            checkInEditingMode();
1036
            checkIsOwnFeature(feature);
1037
            if (feature instanceof EditableFeature) {
1038
                throw new StoreDeleteEditableFeatureException(getName());
1039
            }
1040
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1041

    
1042
            //Update the featureManager and the spatialManager
1043
            featureManager.delete(feature.getReference());
1044
            spatialManager.deleteFeature(feature);
1045

    
1046
            newVersionOfUpdate();
1047
            hasStrongChanges = true;
1048
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1049
        } catch (Exception e) {
1050
            throw new StoreDeleteFeatureException(e, this.getName());
1051
        }
1052
    }
1053

    
1054
    private static EditableFeature lastChangedFeature = null;
1055

    
1056
    public synchronized void insert(EditableFeature feature)
1057
        throws DataException {
1058
        LOG.debug("In editing mode {}, insert feature: {}", new Integer(mode),
1059
            feature);
1060
        try {
1061
            switch (mode) {
1062
            case MODE_QUERY:
1063
                throw new NeedEditingModeException(this.getName());
1064

    
1065
            case MODE_APPEND:
1066
                checkIsOwnFeature(feature);
1067
                if (feature.getSource() != null) {
1068
                    throw new NoNewFeatureInsertException(this.getName());
1069
                }
1070
                this.featureCount = null;
1071
                notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1072
                feature.validate(Feature.UPDATE);
1073
                provider.append(((DefaultEditableFeature) feature).getData());
1074
                hasStrongChanges = true;
1075
                hasInserts = true;
1076
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1077
                break;
1078

    
1079
            case MODE_FULLEDIT:
1080
                if (feature.getSource() != null) {
1081
                    throw new NoNewFeatureInsertException(this.getName());
1082
                }
1083
                commands.insert(feature);
1084
            }
1085
        } catch (Exception e) {
1086
            throw new StoreInsertFeatureException(e, this.getName());
1087
        }
1088
    }
1089

    
1090
    synchronized public void doInsert(EditableFeature feature)
1091
        throws DataException {
1092
        checkIsOwnFeature(feature);
1093

    
1094
        waitForIndexes();
1095

    
1096
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1097
        newVersionOfUpdate();
1098
        if ((lastChangedFeature == null)
1099
            || (lastChangedFeature.getSource() != feature.getSource())) {
1100
            lastChangedFeature = feature;
1101
            feature.validate(Feature.UPDATE);
1102
            lastChangedFeature = null;
1103
        }
1104
        //Update the featureManager and the spatialManager
1105
        ((DefaultEditableFeature) feature).setInserted(true);
1106
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1107

    
1108

    
1109
        featureManager.add(newFeature);
1110
        spatialManager.insertFeature(newFeature);
1111

    
1112
        hasStrongChanges = true;
1113
        hasInserts = true;
1114
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1115
    }
1116

    
1117
    public void update(EditableFeature feature)
1118
    throws DataException {
1119
        if ((feature).getSource() == null) {
1120
            insert(feature);
1121
            return;
1122
        }
1123
        commands.update(feature, feature.getSource());
1124
    }
1125

    
1126
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1127
        throws DataException {
1128
        try {
1129
            checkInEditingMode();
1130
            checkIsOwnFeature(feature);
1131
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature);
1132
            newVersionOfUpdate();
1133
            if ((lastChangedFeature == null)
1134
                || (lastChangedFeature.getSource() != feature.getSource())) {
1135
                lastChangedFeature = feature;
1136
                feature.validate(Feature.UPDATE);
1137
                lastChangedFeature = null;
1138
            }
1139

    
1140
            //Update the featureManager and the spatialManager
1141
            Feature newf = feature.getNotEditableCopy();
1142
            featureManager.update(newf, oldFeature);
1143
            spatialManager.updateFeature(newf, oldFeature);
1144

    
1145
            hasStrongChanges = true;
1146
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1147
        } catch (Exception e) {
1148
            throw new StoreUpdateFeatureException(e, this.getName());
1149
        }
1150
    }
1151

    
1152
    synchronized public void redo() throws RedoException {
1153
        Command redo = commands.getNextRedoCommand();
1154
        try {
1155
            checkInEditingMode();
1156
        } catch (NeedEditingModeException ex) {
1157
            throw new RedoException(redo, ex);
1158
        }
1159
        notifyChange(FeatureStoreNotification.BEFORE_REDO, redo);
1160
        newVersionOfUpdate();
1161
        commands.redo();
1162
        hasStrongChanges = true;
1163
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1164
    }
1165

    
1166
    synchronized public void undo() throws UndoException {
1167
        Command undo = commands.getNextUndoCommand();
1168
        try {
1169
            checkInEditingMode();
1170
        } catch (NeedEditingModeException ex) {
1171
            throw new UndoException(undo, ex);
1172
        }
1173
        notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo);
1174
        newVersionOfUpdate();
1175
        commands.undo();
1176
        hasStrongChanges = true;
1177
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1178
    }
1179

    
1180
    public List getRedoInfos() {
1181
        if (isEditing() && (commands != null)) {
1182
            return commands.getRedoInfos();
1183
        } else {
1184
            return null;
1185
        }
1186
    }
1187

    
1188
    public List getUndoInfos() {
1189
        if (isEditing() && (commands != null)) {
1190
            return commands.getUndoInfos();
1191
        } else {
1192
            return null;
1193
        }
1194
    }
1195

    
1196
    public synchronized FeatureCommandsStack getCommandsStack()
1197
        throws DataException {
1198
        checkInEditingMode();
1199
        return commands;
1200
    }
1201

    
1202
    synchronized public void cancelEditing() throws DataException {
1203
        spatialManager.cancelModifies();
1204
        try {
1205
            checkInEditingMode();
1206

    
1207
            boolean clearSelection = this.hasStrongChanges;
1208
            if (this.selection instanceof FeatureReferenceSelection) {
1209
                clearSelection = this.hasInserts;
1210
            }
1211
            notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1212
            exitEditingMode();
1213
            if (clearSelection) {
1214
                ((FeatureSelection) this.getSelection()).deselectAll();
1215
            }
1216
            updateIndexes();
1217
            notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1218
        } catch (Exception e) {
1219
            throw new StoreCancelEditingException(e, this.getName());
1220
        }
1221
    }
1222

    
1223
    synchronized public void finishEditing() throws DataException {
1224
        LOG.debug("finish editing of mode: {}", new Integer(mode));
1225
        try {
1226

    
1227
            /*
1228
             * Selection needs to be cleared when editing stops
1229
             * to prevent conflicts with selection remaining from
1230
             * editing mode.
1231
             */
1232
//            ((FeatureSelection) this.getSelection()).deselectAll();
1233

    
1234
            switch (mode) {
1235
            case MODE_QUERY:
1236
                throw new NeedEditingModeException(this.getName());
1237

    
1238
            case MODE_APPEND:
1239
                ((FeatureSelection) this.getSelection()).deselectAll();
1240
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1241
                provider.endAppend();
1242
                exitEditingMode();
1243
                updateIndexes();
1244
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1245
                break;
1246

    
1247
            case MODE_FULLEDIT:
1248
                if (hasStrongChanges && !this.allowWrite()) {
1249
                    throw new WriteNotAllowedException(getName());
1250
                }
1251

    
1252
                if(featureManager.isSelectionCompromised()) {
1253
                    ((FeatureSelection) this.getSelection()).deselectAll();
1254
                };
1255

    
1256
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1257
                if (hasStrongChanges) {
1258
                    validateFeatures(Feature.FINISH_EDITING);
1259

    
1260
                    /*
1261
                     * This will throw a PerformEditingExceptionif the provider
1262
                     * does not accept the changes (for example, an invalid field name)
1263
                     */
1264
                    provider.performChanges(featureManager.getDeleted(),
1265
                        featureManager.getInserted(),
1266
                        featureManager.getUpdated(),
1267
                        featureTypeManager.getFeatureTypesChanged());
1268
                }
1269
                exitEditingMode();
1270
                updateIndexes();
1271
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1272
                break;
1273
            }
1274
        } catch (PerformEditingException pee) {
1275
            throw new WriteException(provider.getSourceId().toString(), pee);
1276
        } catch (Exception e) {
1277
            throw new FinishEditingException(e);
1278
        }
1279
    }
1280

    
1281
    /**
1282
     * Save changes in the provider without leaving the edit mode.
1283
     * Do not call observers to communicate a change of ediding mode.
1284
     * The operation's history is eliminated to prevent inconsistencies
1285
     * in the data.
1286
     *
1287
     * @throws DataException
1288
     */
1289
    synchronized public void commitChanges() throws DataException {
1290
      LOG.debug("commitChanges of mode: {}", new Integer(mode));
1291
      if( !canCommitChanges() ) {
1292
              throw new WriteNotAllowedException(getName());
1293
      }
1294
      try {
1295
        switch (mode) {
1296
        case MODE_QUERY:
1297
          throw new NeedEditingModeException(this.getName());
1298

    
1299
        case MODE_APPEND:
1300
          this.provider.endAppend();
1301
          exitEditingMode();
1302
          invalidateIndexes();
1303
          this.provider.beginAppend();
1304
          hasInserts = false;
1305
          break;
1306

    
1307
        case MODE_FULLEDIT:
1308
          if (hasStrongChanges && !this.allowWrite()) {
1309
            throw new WriteNotAllowedException(getName());
1310
          }
1311
          if (hasStrongChanges) {
1312
            validateFeatures(Feature.FINISH_EDITING);
1313
            provider.performChanges(featureManager.getDeleted(),
1314
              featureManager.getInserted(),
1315
              featureManager.getUpdated(),
1316
              featureTypeManager.getFeatureTypesChanged());
1317
          }
1318
          invalidateIndexes();
1319
          featureManager =
1320
            new FeatureManager(new MemoryExpansionAdapter());
1321
          featureTypeManager =
1322
            new FeatureTypeManager(this, new MemoryExpansionAdapter());
1323
          spatialManager =
1324
            new SpatialManager(this, provider.getEnvelope());
1325

    
1326
          commands =
1327
            new DefaultFeatureCommandsStack(this, featureManager,
1328
              spatialManager, featureTypeManager);
1329
          featureCount = null;
1330
          hasStrongChanges = false;
1331
          hasInserts = false;
1332
          break;
1333
        }
1334
      } catch (Exception e) {
1335
        throw new FinishEditingException(e);
1336
      }
1337
    }
1338

    
1339
    synchronized public boolean canCommitChanges() throws DataException {
1340
        if ( !this.allowWrite()) {
1341
                return false;
1342
        }
1343
            switch (mode) {
1344
            default:
1345
        case MODE_QUERY:
1346
                return false;
1347

    
1348
        case MODE_APPEND:
1349
                return true;
1350

    
1351
        case MODE_FULLEDIT:
1352
            List types = this.getFeatureTypes();
1353
            for( int i=0; i<types.size(); i++ ) {
1354
                    Object type = types.get(i);
1355
                    if( type instanceof DefaultEditableFeatureType ) {
1356
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1357
                                    return false;
1358
                            }
1359
                    }
1360
            }
1361
            return true;
1362
            }
1363
    }
1364

    
1365
    public void beginEditingGroup(String description)
1366
        throws NeedEditingModeException {
1367
        checkInEditingMode();
1368
        commands.startComplex(description);
1369
    }
1370

    
1371
    public void endEditingGroup() throws NeedEditingModeException {
1372
        checkInEditingMode();
1373
        commands.endComplex();
1374
    }
1375

    
1376
    public boolean isAppendModeSupported() {
1377
        return this.provider.supportsAppendMode();
1378
    }
1379

    
1380
    public void export(DataServerExplorer explorer, String provider,
1381
        NewFeatureStoreParameters params) throws DataException {
1382

    
1383
        if (this.getFeatureTypes().size() != 1) {
1384
            throw new NotYetImplemented(
1385
                "export whith more than one type not yet implemented");
1386
        }
1387
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1388
        FeatureStore target = null;
1389
        FeatureSet features = null;
1390
        DisposableIterator iterator = null;
1391
        try {
1392
            FeatureType type = this.getDefaultFeatureType();
1393
            if ((params.getDefaultFeatureType() == null)
1394
                || (params.getDefaultFeatureType().size() == 0)) {
1395
                params.setDefaultFeatureType(type.getEditable());
1396

    
1397
            }
1398
            explorer.add(provider, params, true);
1399

    
1400
            DataManager manager = DALLocator.getDataManager();
1401
            target = (FeatureStore) manager.openStore(provider, params);
1402
            FeatureType targetType = target.getDefaultFeatureType();
1403

    
1404
            target.edit(MODE_APPEND);
1405
            FeatureAttributeDescriptor[] pk = type.getPrimaryKey();
1406
            if (featureSelection.getSize() > 0) {
1407
                features = this.getFeatureSelection();
1408
            } else {
1409
                if ((pk != null) && (pk.length > 0)) {
1410
                    FeatureQuery query = createFeatureQuery();
1411
                    for (int i = 0; i < pk.length; i++) {
1412
                        query.getOrder().add(pk[i].getName(), true);
1413
                    }
1414
                    features = this.getFeatureSet(query);
1415
                } else {
1416
                    features = this.getFeatureSet();
1417
                }
1418
            }
1419
            iterator = features.fastIterator();
1420
            while (iterator.hasNext()) {
1421
                DefaultFeature feature = (DefaultFeature) iterator.next();
1422
                target.insert(target.createNewFeature(targetType, feature));
1423
            }
1424
            target.finishEditing();
1425
            target.dispose();
1426
        } catch (Exception e) {
1427
            throw new DataExportException(e, params.toString());
1428
        } finally {
1429
            dispose(iterator);
1430
            dispose(features);
1431
            dispose(target);
1432
        }
1433
    }
1434

    
1435
    //
1436
    // ====================================================================
1437
    // Obtencion de datos
1438
    // getDataCollection, getFeatureCollection
1439
    //
1440

    
1441
    public DataSet getDataSet() throws DataException {
1442
        checkNotInAppendMode();
1443
        FeatureQuery query =
1444
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1445
        return new DefaultFeatureSet(this, query);
1446
    }
1447

    
1448
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1449
        checkNotInAppendMode();
1450
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1451
    }
1452

    
1453
    public void getDataSet(Observer observer) throws DataException {
1454
        checkNotInAppendMode();
1455
        this.getFeatureSet(null, observer);
1456
    }
1457

    
1458
    public void getDataSet(DataQuery dataQuery, Observer observer)
1459
        throws DataException {
1460
        checkNotInAppendMode();
1461
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1462
    }
1463

    
1464
    @Override
1465
    public FeatureSet getFeatureSet() throws DataException {
1466
        return this.getFeatureSet((FeatureQuery)null);
1467
    }
1468

    
1469
    @Override
1470
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1471
        throws DataException {
1472
        checkNotInAppendMode();
1473
        if( featureQuery==null ) {
1474
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1475
        }
1476
        return new DefaultFeatureSet(this, featureQuery);
1477
    }
1478

    
1479
    @Override
1480
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
1481
        try {
1482
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
1483
            return pager.asList();
1484
        } catch (BaseException ex) {
1485
            throw new RuntimeException("Can't create the list of features.", ex);
1486
        }
1487
    }
1488

    
1489
    @Override
1490
    public List<Feature> getFeatures() {
1491
        return this.getFeatures(null, 500);
1492
    }
1493
    
1494
    public void accept(Visitor visitor) throws BaseException {
1495
        FeatureSet set = getFeatureSet();
1496
        try {
1497
            set.accept(visitor);
1498
        } finally {
1499
            set.dispose();
1500
        }
1501
    }
1502

    
1503
    public void accept(Visitor visitor, DataQuery dataQuery)
1504
        throws BaseException {
1505
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
1506
        try {
1507
            set.accept(visitor);
1508
        } finally {
1509
            set.dispose();
1510
        }
1511
    }
1512

    
1513
    public FeatureType getFeatureType(FeatureQuery featureQuery)
1514
        throws DataException {
1515
        DefaultFeatureType fType =
1516
            (DefaultFeatureType) this.getFeatureType(featureQuery
1517
                .getFeatureTypeId());
1518
        if( featureQuery.hasAttributeNames() || featureQuery.hasConstantsAttributeNames() ) {
1519
            return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames() );
1520
        }
1521
        return fType;
1522
    }
1523

    
1524
    public void getFeatureSet(Observer observer) throws DataException {
1525
        checkNotInAppendMode();
1526
        this.getFeatureSet(null, observer);
1527
    }
1528

    
1529
    public void getFeatureSet(FeatureQuery query, Observer observer)
1530
        throws DataException {
1531
        class LoadInBackGround implements Runnable {
1532

    
1533
            private FeatureStore store;
1534
            private FeatureQuery query;
1535
            private Observer observer;
1536

    
1537
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
1538
                Observer observer) {
1539
                this.store = store;
1540
                this.query = query;
1541
                this.observer = observer;
1542
            }
1543

    
1544
            void notify(FeatureStoreNotification theNotification) {
1545
                observer.update(store, theNotification);
1546
                return;
1547
            }
1548

    
1549
            public void run() {
1550
                FeatureSet set = null;
1551
                try {
1552
                    set = store.getFeatureSet(query);
1553
                    notify(new DefaultFeatureStoreNotification(store,
1554
                        FeatureStoreNotification.LOAD_FINISHED, set));
1555
                } catch (Exception e) {
1556
                    notify(new DefaultFeatureStoreNotification(store,
1557
                        FeatureStoreNotification.LOAD_FINISHED, e));
1558
                } finally {
1559
                    dispose(set);
1560
                }
1561
            }
1562
        }
1563

    
1564
        checkNotInAppendMode();
1565
        if (query == null) {
1566
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
1567
        }
1568
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
1569
        Thread thread = new Thread(task, "Load Feature Set in background");
1570
        thread.start();
1571
    }
1572

    
1573
    public Feature getFeatureByReference(FeatureReference reference)
1574
        throws DataException {
1575
        checkNotInAppendMode();
1576
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
1577
        FeatureType featureType;
1578
        if (ref.getFeatureTypeId() == null) {
1579
            featureType = this.getDefaultFeatureType();
1580
        } else {
1581
            featureType = this.getFeatureType(ref.getFeatureTypeId());
1582
        }
1583
        return this.getFeatureByReference(reference, featureType);
1584
    }
1585

    
1586
    public Feature getFeatureByReference(FeatureReference reference,
1587
        FeatureType featureType) throws DataException {
1588
        checkNotInAppendMode();
1589
        featureType = fixFeatureType((DefaultFeatureType) featureType);
1590
        if (this.mode == MODE_FULLEDIT) {
1591
            Feature f = featureManager.get(reference, this, featureType);
1592
            if (f != null) {
1593
                return f;
1594
            }
1595
        }
1596

    
1597
        FeatureType sourceFeatureType = featureType;
1598
        if (!this.transforms.isEmpty()) {
1599
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
1600
        }
1601
        // TODO comprobar que el id es de este store
1602

    
1603
        DefaultFeature feature =
1604
            new DefaultFeature(this,
1605
                this.provider.getFeatureProviderByReference(
1606
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
1607

    
1608
        if (!this.transforms.isEmpty()) {
1609
            return this.transforms.applyTransform(feature, featureType);
1610
        }
1611
        return feature;
1612
    }
1613

    
1614
    //
1615
    // ====================================================================
1616
    // Gestion de features
1617
    //
1618

    
1619
    private FeatureType fixFeatureType(DefaultFeatureType type)
1620
        throws DataException {
1621
        FeatureType original = this.getDefaultFeatureType();
1622

    
1623
        if ((type == null) || type.equals(original)) {
1624
            return original;
1625
        } else {
1626
            if (!type.isSubtypeOf(original)) {
1627
                Iterator iter = this.getFeatureTypes().iterator();
1628
                FeatureType tmpType;
1629
                boolean found = false;
1630
                while (iter.hasNext()) {
1631
                    tmpType = (FeatureType) iter.next();
1632
                    if (type.equals(tmpType)) {
1633
                        return type;
1634

    
1635
                    } else
1636
                        if (type.isSubtypeOf(tmpType)) {
1637
                            found = true;
1638
                            original = tmpType;
1639
                            break;
1640
                        }
1641

    
1642
                }
1643
                if (!found) {
1644
                    throw new IllegalFeatureTypeException(getName());
1645
                }
1646
            }
1647
        }
1648

    
1649
        // Checks that type has all fields of pk
1650
        // else add the missing attributes at the end.
1651
        if (!original.hasOID()) {
1652
            // Gets original pk attributes
1653
            DefaultEditableFeatureType edOriginal =
1654
                (DefaultEditableFeatureType) original.getEditable();
1655
            FeatureAttributeDescriptor orgAttr;
1656
            Iterator edOriginalIter = edOriginal.iterator();
1657
            while (edOriginalIter.hasNext()) {
1658
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1659
                if (!orgAttr.isPrimaryKey()) {
1660
                    edOriginalIter.remove();
1661
                }
1662
            }
1663

    
1664
            // Checks if all pk attributes are in type
1665
            Iterator typeIterator;
1666
            edOriginalIter = edOriginal.iterator();
1667
            FeatureAttributeDescriptor attr;
1668
            while (edOriginalIter.hasNext()) {
1669
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1670
                typeIterator = type.iterator();
1671
                while (typeIterator.hasNext()) {
1672
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
1673
                    if (attr.getName().equals(orgAttr.getName())) {
1674
                        edOriginalIter.remove();
1675
                        break;
1676
                    }
1677
                }
1678
            }
1679

    
1680
            // add missing pk attributes if any
1681
            if (edOriginal.size() > 0) {
1682
                boolean isEditable = type instanceof DefaultEditableFeatureType;
1683
                DefaultEditableFeatureType edType =
1684
                    (DefaultEditableFeatureType) original.getEditable();
1685
                edType.clear();
1686
                edType.addAll(type);
1687
                edType.addAll(edOriginal);
1688
                if (!isEditable) {
1689
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
1690
                }
1691
            }
1692

    
1693
        }
1694

    
1695
        return type;
1696
    }
1697

    
1698
    public void validateFeatures(int mode) throws DataException {
1699
        FeatureSet collection = null;
1700
        DisposableIterator iter = null;
1701
        try {
1702
            checkNotInAppendMode();
1703
            collection = this.getFeatureSet();
1704
            iter = collection.fastIterator();
1705
            long previousVersionOfUpdate = currentVersionOfUpdate();
1706
            while (iter.hasNext()) {
1707
                ((DefaultFeature) iter.next()).validate(mode);
1708
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
1709
                    throw new ConcurrentDataModificationException(getName());
1710
                }
1711
            }
1712
        } catch (Exception e) {
1713
            throw new ValidateFeaturesException(e, getName());
1714
        } finally {
1715
            dispose(iter);
1716
            dispose(collection);
1717
        }
1718
    }
1719

    
1720
    public FeatureType getDefaultFeatureType() throws DataException {
1721
        try {
1722

    
1723
            if (isEditing()) {
1724
                FeatureType auxFeatureType =
1725
                    featureTypeManager.getType(defaultFeatureType.getId());
1726
                if (auxFeatureType != null) {
1727
                    return avoidEditable(auxFeatureType);
1728
                }
1729
            }
1730
            FeatureType type = this.transforms.getDefaultFeatureType();
1731
            if (type != null) {
1732
                return avoidEditable(type);
1733
            }
1734

    
1735
            return avoidEditable(defaultFeatureType);
1736

    
1737
        } catch (Exception e) {
1738
            throw new GetFeatureTypeException(e, getName());
1739
        }
1740
    }
1741

    
1742
    private FeatureType avoidEditable(FeatureType ft) {
1743
        if (ft instanceof EditableFeatureType) {
1744
            return ((EditableFeatureType) ft).getNotEditableCopy();
1745
        } else {
1746
            return ft;
1747
        }
1748
    }
1749

    
1750
    public FeatureType getFeatureType(String featureTypeId)
1751
        throws DataException {
1752
        if (featureTypeId == null) {
1753
            return this.getDefaultFeatureType();
1754
        }
1755
        try {
1756
            if (isEditing()) {
1757
                FeatureType auxFeatureType =
1758
                    featureTypeManager.getType(featureTypeId);
1759
                if (auxFeatureType != null) {
1760
                    return auxFeatureType;
1761
                }
1762
            }
1763
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
1764
            if (type != null) {
1765
                return type;
1766
            }
1767
            Iterator iter = this.featureTypes.iterator();
1768
            while (iter.hasNext()) {
1769
                type = (FeatureType) iter.next();
1770
                if (type.getId().equals(featureTypeId)) {
1771
                    return type;
1772
                }
1773
            }
1774
            return null;
1775
        } catch (Exception e) {
1776
            throw new GetFeatureTypeException(e, getName());
1777
        }
1778
    }
1779

    
1780
    public FeatureType getProviderDefaultFeatureType() {
1781
        return defaultFeatureType;
1782
    }
1783

    
1784
    public List getFeatureTypes() throws DataException {
1785
        try {
1786
            List types;
1787
            if (isEditing()) {
1788
                types = new ArrayList();
1789
                Iterator it = featureTypes.iterator();
1790
                while (it.hasNext()) {
1791
                    FeatureType type = (FeatureType) it.next();
1792
                    FeatureType typeaux =
1793
                        featureTypeManager.getType(type.getId());
1794
                    if (typeaux != null) {
1795
                        types.add(typeaux);
1796
                    } else {
1797
                        types.add(type);
1798
                    }
1799
                }
1800
                it = featureTypeManager.newsIterator();
1801
                while (it.hasNext()) {
1802
                    FeatureType type = (FeatureType) it.next();
1803
                    types.add(type);
1804
                }
1805
            } else {
1806
                types = this.transforms.getFeatureTypes();
1807
                if (types == null) {
1808
                    types = featureTypes;
1809
                }
1810
            }
1811
            return Collections.unmodifiableList(types);
1812
        } catch (Exception e) {
1813
            throw new GetFeatureTypeException(e, getName());
1814
        }
1815
    }
1816

    
1817
    public List getProviderFeatureTypes() throws DataException {
1818
        return Collections.unmodifiableList(this.featureTypes);
1819
    }
1820

    
1821
    public Feature createFeature(FeatureProvider data) throws DataException {
1822
        DefaultFeature feature = new DefaultFeature(this, data);
1823
        return feature;
1824
    }
1825

    
1826
    public Feature createFeature(FeatureProvider data, FeatureType type)
1827
        throws DataException {
1828
        // FIXME: falta por implementar
1829
        // Comprobar si es un subtipo del feature de data
1830
        // y construir un feature usando el subtipo.
1831
        // Probablemente requiera generar una copia del data.
1832
        throw new NotYetImplemented();
1833
    }
1834

    
1835
    public EditableFeature createNewFeature(FeatureType type,
1836
        Feature defaultValues) throws DataException {
1837
        try {
1838
            FeatureProvider data = createNewFeatureProvider(type);
1839
            DefaultEditableFeature feature =
1840
                new DefaultEditableFeature(this, data);
1841
            feature.initializeValues(defaultValues);
1842
            data.setNew(true);
1843

    
1844
            return feature;
1845
        } catch (Exception e) {
1846
            throw new CreateFeatureException(e, getName());
1847
        }
1848
    }
1849

    
1850
    private FeatureProvider createNewFeatureProvider(FeatureType type)
1851
        throws DataException {
1852
        type = this.fixFeatureType((DefaultFeatureType) type);
1853
        FeatureProvider data = this.provider.createFeatureProvider(type);
1854
        data.setNew(true);
1855
        if (type.hasOID() && (data.getOID() == null)) {
1856
            data.setOID(this.provider.createNewOID());
1857
        } else {
1858
            data.setOID(this.getTemporalOID());
1859
        }
1860
        return data;
1861

    
1862
    }
1863

    
1864
    public EditableFeature createNewFeature(FeatureType type,
1865
        boolean defaultValues) throws DataException {
1866
        try {
1867
            FeatureProvider data = createNewFeatureProvider(type);
1868
            DefaultEditableFeature feature =
1869
                new DefaultEditableFeature(this, data);
1870
            if (defaultValues) {
1871
                feature.initializeValues();
1872
            }
1873
            return feature;
1874
        } catch (Exception e) {
1875
            throw new CreateFeatureException(e, getName());
1876
        }
1877
    }
1878

    
1879
    public EditableFeature createNewFeature(boolean defaultValues)
1880
        throws DataException {
1881
        return this.createNewFeature(this.getDefaultFeatureType(),
1882
            defaultValues);
1883
    }
1884

    
1885
    public EditableFeature createNewFeature() throws DataException {
1886
        return this.createNewFeature(this.getDefaultFeatureType(), true);
1887
    }
1888

    
1889
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
1890
        FeatureType ft = this.getDefaultFeatureType();
1891
        EditableFeature f = this.createNewFeature(ft, false);
1892
        Iterator it = ft.iterator();
1893
        while(it.hasNext()) {
1894
            FeatureAttributeDescriptor desc = (FeatureAttributeDescriptor) it.next();
1895
            try {
1896
                f.set(desc.getName(), defaultValues.get(desc.getName()));
1897
            } catch(Throwable th) {
1898
                // Ignore
1899
            }
1900
        }
1901
        return f;
1902
    }
1903

    
1904
    public EditableFeatureType createFeatureType() {
1905
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType();
1906
        return ftype;
1907
    }
1908

    
1909
    public EditableFeatureType createFeatureType(String id) {
1910
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(id);
1911
        return ftype;
1912
    }
1913

    
1914
    //
1915
    // ====================================================================
1916
    // Index related methods
1917
    //
1918

    
1919
    public FeatureIndexes getIndexes() {
1920
        return this.indexes;
1921
    }
1922

    
1923
    public FeatureIndex createIndex(FeatureType featureType,
1924
        String attributeName, String indexName) throws DataException {
1925
        return createIndex(null, featureType, attributeName, indexName);
1926
    }
1927

    
1928
    public FeatureIndex createIndex(String indexTypeName,
1929
        FeatureType featureType, String attributeName, String indexName)
1930
        throws DataException {
1931

    
1932
        return createIndex(indexTypeName, featureType, attributeName,
1933
            indexName, false, null);
1934
    }
1935

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

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

    
1947
        return createIndex(indexTypeName, featureType, attributeName,
1948
            indexName, true, observer);
1949
    }
1950

    
1951
    private FeatureIndex createIndex(String indexTypeName,
1952
        FeatureType featureType, String attributeName, String indexName,
1953
        boolean background, final Observer observer) throws DataException {
1954

    
1955
        checkNotInAppendMode();
1956
        FeatureIndexProviderServices index = null;
1957
        index =
1958
            dataManager.createFeatureIndexProvider(indexTypeName, this,
1959
                featureType, indexName,
1960
                featureType.getAttributeDescriptor(attributeName));
1961

    
1962
        try {
1963
            index.fill(background, observer);
1964
        } catch (FeatureIndexException e) {
1965
            throw new InitializeException(index.getName(), e);
1966
        }
1967

    
1968
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
1969
        return index;
1970
    }
1971

    
1972
    //
1973
    // ====================================================================
1974
    // Transforms related methods
1975
    //
1976

    
1977
    public FeatureStoreTransforms getTransforms() {
1978
        return this.transforms;
1979
    }
1980

    
1981
    public FeatureQuery createFeatureQuery() {
1982
        return new DefaultFeatureQuery();
1983
    }
1984

    
1985
    public DataQuery createQuery() {
1986
        return createFeatureQuery();
1987
    }
1988

    
1989
    //
1990
    // ====================================================================
1991
    // UndoRedo related methods
1992
    //
1993

    
1994
    public boolean canRedo() {
1995
        return commands.canRedo();
1996
    }
1997

    
1998
    public boolean canUndo() {
1999
        return commands.canUndo();
2000
    }
2001

    
2002
    public void redo(int num) throws RedoException {
2003
        for (int i = 0; i < num; i++) {
2004
            redo();
2005
        }
2006
    }
2007

    
2008
    public void undo(int num) throws UndoException {
2009
        for (int i = 0; i < num; i++) {
2010
            undo();
2011
        }
2012
    }
2013

    
2014
    //
2015
    // ====================================================================
2016
    // Metadata related methods
2017
    //
2018

    
2019
    public Object getMetadataID() {
2020
        return this.provider.getSourceId();
2021
    }
2022

    
2023
    public void delegate(DynObject dynObject) {
2024
        this.metadata.delegate(dynObject);
2025
    }
2026

    
2027
    public DynClass getDynClass() {
2028
        return this.metadata.getDynClass();
2029
    }
2030

    
2031
        public Object getDynValue(String name) throws DynFieldNotFoundException {
2032
                if( this.transforms.hasDynValue(name) ) {
2033
                        return this.transforms.getDynValue(name);
2034
                }
2035
                if (this.metadata.hasDynValue(name)) {
2036
                        return this.metadata.getDynValue(name);
2037
                }
2038
                if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2039
                        return this.provider.getProviderName();
2040
                } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2041
                        return this.provider.getSourceId();
2042
                } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2043
                        try {
2044
                                return this.getDefaultFeatureType();
2045
                        } catch (DataException e) {
2046
                                return null;
2047
                        }
2048
                }
2049
                return this.metadata.getDynValue(name);
2050
        }
2051

    
2052
    public boolean hasDynValue(String name) {
2053
                if( this.transforms.hasDynValue(name) ) {
2054
                        return true;
2055
                }
2056
        return this.metadata.hasDynValue(name);
2057
    }
2058

    
2059
    public void implement(DynClass dynClass) {
2060
        this.metadata.implement(dynClass);
2061
    }
2062

    
2063
    public Object invokeDynMethod(String name, Object[] args)
2064
        throws DynMethodException {
2065
        return this.metadata.invokeDynMethod(this, name, args);
2066
    }
2067

    
2068
    public Object invokeDynMethod(int code, Object[] args)
2069
        throws DynMethodException {
2070
        return this.metadata.invokeDynMethod(this, code, args);
2071
    }
2072

    
2073
    public void setDynValue(String name, Object value)
2074
        throws DynFieldNotFoundException {
2075
                if( this.transforms.hasDynValue(name) ) {
2076
                        this.transforms.setDynValue(name, value);
2077
                        return;
2078
                }
2079
        this.metadata.setDynValue(name, value);
2080

    
2081
    }
2082

    
2083
    /*
2084
     * (non-Javadoc)
2085
     *
2086
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2087
     */
2088
    public Set getMetadataChildren() {
2089
        return this.metadataChildren;
2090
    }
2091

    
2092
    /*
2093
     * (non-Javadoc)
2094
     *
2095
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2096
     */
2097
    public String getMetadataName() {
2098
        return this.provider.getProviderName();
2099
    }
2100

    
2101
    public FeatureTypeManager getFeatureTypeManager() {
2102
        return this.featureTypeManager;
2103
    }
2104

    
2105
    public long getFeatureCount() throws DataException {
2106
        if (featureCount == null) {
2107
            featureCount = new Long(this.provider.getFeatureCount());
2108
        }
2109
        if (this.isEditing()) {
2110
            if(this.isAppending()) {
2111
                try{
2112
                    throw new IllegalStateException();
2113
                } catch(IllegalStateException e) {
2114
                    LOG.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND");
2115
                    e.printStackTrace();
2116
                }
2117
                return -1;
2118
            } else {
2119
                return featureCount.longValue()
2120
                    + this.featureManager.getDeltaSize();
2121
            }
2122
        }
2123
        return featureCount.longValue();
2124
    }
2125

    
2126
    private Long getTemporalOID() {
2127
        return new Long(this.temporalOid++);
2128
    }
2129

    
2130
    public FeatureType getProviderFeatureType(String featureTypeId) {
2131
        if (featureTypeId == null) {
2132
            return this.defaultFeatureType;
2133
        }
2134
        FeatureType type;
2135
        Iterator iter = this.featureTypes.iterator();
2136
        while (iter.hasNext()) {
2137
            type = (FeatureType) iter.next();
2138
            if (type.getId().equals(featureTypeId)) {
2139
                return type;
2140
            }
2141
        }
2142
        return null;
2143
    }
2144

    
2145
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2146
        return ((DefaultFeature) feature).getData();
2147
    }
2148

    
2149
    public DataStore getStore() {
2150
        return this;
2151
    }
2152

    
2153
    public FeatureStore getFeatureStore() {
2154
        return this;
2155
    }
2156

    
2157
    public void createCache(String name, DynObject parameters)
2158
        throws DataException {
2159
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2160
        if (cache == null) {
2161
            throw new CreateException("FeaureCacheProvider", null);
2162
        }
2163
        cache.apply(this, provider);
2164
        provider = cache;
2165

    
2166
        featureCount = null;
2167
    }
2168

    
2169
    public FeatureCache getCache() {
2170
        return cache;
2171
    }
2172

    
2173
    public void clear() {
2174
        if (metadata != null) {
2175
            metadata.clear();
2176
        }
2177
    }
2178

    
2179
    public String getName() {
2180
        return this.provider.getName();
2181
    }
2182

    
2183
    public String getFullName() {
2184
        try {
2185
            return this.provider.getFullName();
2186
        } catch(Throwable th) {
2187
            return null;
2188
        }
2189
    }
2190

    
2191
    public String getProviderName() {
2192
        return this.provider.getProviderName();
2193
    }
2194

    
2195
    public boolean isKnownEnvelope() {
2196
        return this.provider.isKnownEnvelope();
2197
    }
2198

    
2199
    public boolean hasRetrievedFeaturesLimit() {
2200
        return this.provider.hasRetrievedFeaturesLimit();
2201
    }
2202

    
2203
    public int getRetrievedFeaturesLimit() {
2204
        return this.provider.getRetrievedFeaturesLimit();
2205
    }
2206

    
2207
    public Interval getInterval() {
2208
        return this.provider.getInterval();
2209
    }
2210

    
2211
    public Collection getTimes() {
2212
        return this.provider.getTimes();
2213
    }
2214

    
2215
    public Collection getTimes(Interval interval) {
2216
        return this.provider.getTimes(interval);
2217
    }
2218

    
2219
    /* (non-Javadoc)
2220
     * @see java.lang.Object#clone()
2221
     */
2222
    public Object clone() throws CloneNotSupportedException {
2223

    
2224
        DataStoreParameters dsp = getParameters();
2225

    
2226
        DefaultFeatureStore cloned_store = null;
2227

    
2228
        try {
2229
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2230
                openStore(this.getProviderName(), dsp);
2231
            if (transforms != null) {
2232
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2233
                cloned_store.transforms.setStoreForClone(cloned_store);
2234
            }
2235
        } catch (Exception e) {
2236
            throw new CloneException(e);
2237
        }
2238
        return cloned_store;
2239

    
2240
    }
2241

    
2242
    public Feature getFeature(DynObject dynobject) {
2243
        if (dynobject instanceof DynObjectFeatureFacade){
2244
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2245
            return f;
2246
        }
2247
        return null;
2248
    }
2249

    
2250
    public Iterator iterator() {
2251
        try {
2252
            return this.getFeatureSet().fastIterator();
2253
        } catch (DataException ex) {
2254
            throw new RuntimeException(ex);
2255
        }
2256
    }
2257

    
2258
    @Override
2259
    public ExpressionEvaluator createExpression() {
2260
        if( this.provider instanceof FeatureStoreProvider_v2 ) {
2261
            return ((FeatureStoreProvider_v2)this.provider).createExpression();
2262
        }
2263
        return new SQLBuilderBase();
2264
    }
2265
 
2266

    
2267
    public FeatureSet features() throws DataException {
2268
        // This is to avoid jython to create a property with this name
2269
        // to access method getFeatures.
2270
        return this.getFeatureSet();
2271
    }
2272
    
2273
}