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

History | View | Annotate | Download (77.2 KB)

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

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

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

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

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

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

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

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

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

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

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

    
182
    private DefaultDataManager dataManager = null;
183

    
184
    private FeatureStoreProvider provider = null;
185

    
186
    private DefaultFeatureIndexes indexes;
187

    
188
    private DefaultFeatureStoreTransforms transforms;
189

    
190
    DelegatedDynObject metadata;
191

    
192
    private Set metadataChildren;
193

    
194
    private Long featureCount = null;
195

    
196
    private long temporalOid = 0;
197

    
198
    private FeatureCacheProvider cache;
199

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

    
209
    public DefaultFeatureStore() {
210

    
211
    }
212

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

    
217
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
218

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

    
224
        this.dataManager = (DefaultDataManager) dataManager;
225

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

    
234
    }
235

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
448
        }
449

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

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

    
457
    }
458

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

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

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

    
518
                }
519

    
520
            }
521

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

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

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

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

    
554
    }
555

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
702
    }
703

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

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

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

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

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

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

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

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

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

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

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

    
765
    }
766

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

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

    
774
    }
775

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

    
779
    }
780

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

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

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

    
796
    }
797

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

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

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

    
821
                }
822

    
823
            }
824
    }
825

    
826
    //
827
    // ====================================================================
828
    // Edicion
829
    //
830

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

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

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

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

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

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

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

    
871
        }
872

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

    
877
        featureCount = null;
878

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1053
    private static EditableFeature lastChangedFeature = null;
1054

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

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

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

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

    
1093
        waitForIndexes();
1094

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

    
1107

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1347
        case MODE_APPEND:
1348
                return true;
1349

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1692
        }
1693

    
1694
        return type;
1695
    }
1696

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

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

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

    
1734
            return avoidEditable(defaultFeatureType);
1735

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

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

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

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

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

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

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

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

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

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

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

    
1861
    }
1862

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2080
    }
2081

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

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

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

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

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

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

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

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

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

    
2156
//    public void createCache(String name, DynObject parameters)
2157
//        throws DataException {
2158
//        cache = dataManager.createFeatureCacheProvider(name, parameters);
2159
//        if (cache == null) {
2160
//            throw new CreateException("FeaureCacheProvider", null);
2161
//        }
2162
//        cache.apply(this, provider);
2163
//        provider = cache;
2164
//
2165
//        featureCount = null;
2166
//    }
2167
//
2168
//    public FeatureCache getCache() {
2169
//        return cache;
2170
//    }
2171

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

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

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

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

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

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

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

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

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

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

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

    
2223
        DataStoreParameters dsp = getParameters();
2224

    
2225
        DefaultFeatureStore cloned_store = null;
2226

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

    
2239
    }
2240

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

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

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