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

History | View | Annotate | Download (76.3 KB)

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

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

    
27
import java.util.ArrayList;
28
import java.util.Collection;
29
import java.util.Collections;
30
import java.util.HashMap;
31
import java.util.HashSet;
32
import java.util.Iterator;
33
import java.util.List;
34
import java.util.Map;
35
import java.util.Map.Entry;
36
import java.util.Set;
37

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

    
149
public class DefaultFeatureStore extends AbstractDisposable implements
150
    DataStoreInitializer, FeatureStoreProviderServices, FeatureStore, Observer {
151

    
152
    private static final Logger LOG = LoggerFactory
153
        .getLogger(DefaultFeatureStore.class);
154

    
155
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
156

    
157
    private DataStoreParameters parameters = null;
158
    private FeatureSelection selection;
159
    private FeatureLocks locks;
160

    
161
    private DelegateWeakReferencingObservable delegateObservable =
162
        new DelegateWeakReferencingObservable(this);
163

    
164
    private FeatureCommandsStack commands;
165
    private FeatureTypeManager featureTypeManager;
166
    private FeatureManager featureManager;
167
    private SpatialManager spatialManager;
168

    
169
    private FeatureType defaultFeatureType = null;
170
    private List featureTypes = new ArrayList();
171

    
172
    private int mode = MODE_QUERY;
173
    private long versionOfUpdate = 0;
174
    private boolean hasStrongChanges = true;
175
    private boolean hasInserts = true;
176

    
177
    private DefaultDataManager dataManager = null;
178

    
179
    private FeatureStoreProvider provider = null;
180

    
181
    private DefaultFeatureIndexes indexes;
182

    
183
    private DefaultFeatureStoreTransforms transforms;
184

    
185
    DelegatedDynObject metadata;
186

    
187
    private Set metadataChildren;
188

    
189
    private Long featureCount = null;
190

    
191
    private long temporalOid = 0;
192

    
193
    private FeatureCacheProvider cache;
194

    
195
    /*
196
     * TODO:
197
     *
198
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
199
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
200
     * featureType al que se le han cambiado las reglas de validacion cuando
201
     * hasStrongChanges=false.
202
     */
203

    
204
    public DefaultFeatureStore() {
205

    
206
    }
207

    
208
    public void intializePhase1(DataManager dataManager,
209
        DataStoreParameters parameters) throws InitializeException {
210

    
211
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
212

    
213
        this.metadata =
214
            (DelegatedDynObject) dynManager.createDynObject(
215
                METADATA_DEFINITION_NAME, MetadataManager.METADATA_NAMESPACE);
216

    
217
        this.dataManager = (DefaultDataManager) dataManager;
218

    
219
        this.parameters = parameters;
220
        this.transforms = new DefaultFeatureStoreTransforms(this);
221
        try {
222
            indexes = new DefaultFeatureIndexes(this);
223
        } catch (DataException e) {
224
            throw new InitializeException(e);
225
        }
226

    
227
    }
228

    
229
    public void intializePhase2(DataStoreProvider provider) {
230
        this.provider = (FeatureStoreProvider) provider;
231
        this.delegate(provider);
232
        this.metadataChildren = new HashSet();
233
        this.metadataChildren.add(provider);
234
    }
235

    
236
    public DataStoreParameters getParameters() {
237
        return parameters;
238
    }
239

    
240
    public int getMode() {
241
        return this.mode;
242
    }
243

    
244
    public DataManager getManager() {
245
        return this.dataManager;
246
    }
247

    
248
    public Iterator getChildren() {
249
        return this.provider.getChilds();
250
    }
251

    
252
    public FeatureStoreProvider getProvider() {
253
        return this.provider;
254
    }
255

    
256
    public FeatureManager getFeatureManager() {
257
        return this.featureManager;
258
    }
259

    
260
    public void setFeatureTypes(List types, FeatureType defaultType) {
261
        this.featureTypes = types;
262
        this.defaultFeatureType = defaultType;
263
    }
264

    
265
    public void open() throws OpenException {
266
        if (this.mode != MODE_QUERY) {
267
            // TODO: Se puede hacer un open estando en edicion ?
268
            try {
269
                throw new IllegalStateException();
270
            } catch(Exception ex) {
271
                LOG.warn("Opening a store in editing/append mode ("+this.getFullName()+").",ex);
272
            }
273
        }
274
        this.notifyChange(DataStoreNotification.BEFORE_OPEN);
275
        this.provider.open();
276
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
277
    }
278

    
279
    public void refresh() throws OpenException, InitializeException {
280
        if (this.mode != MODE_QUERY) {
281
            throw new IllegalStateException();
282
        }
283
        this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH);
284
        this.featureCount = null;
285
        this.provider.refresh();
286
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
287
    }
288

    
289
    public void close() throws CloseException {
290
        if (this.mode != MODE_QUERY) {
291
            // TODO: Se puede hacer un close estando en edicion ?
292
            try {
293
                throw new IllegalStateException();
294
            } catch(Exception ex) {
295
                LOG.warn("Clossing a store in editing/append mode ("+this.getFullName()+").",ex);
296
            }
297
        }
298
        this.notifyChange(DataStoreNotification.BEFORE_CLOSE);
299
        this.featureCount = null;
300
        this.provider.close();
301
        this.notifyChange(DataStoreNotification.AFTER_CLOSE);
302
    }
303

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

    
327
        if (this.featureTypeManager != null) {
328
            this.featureTypeManager.dispose();
329
            this.featureTypeManager = null;
330
        }
331

    
332
        this.featureManager = null;
333
        this.spatialManager = null;
334

    
335
        this.parameters = null;
336
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
337
        if (delegateObservable != null) {
338
            this.delegateObservable.deleteObservers();
339
            this.delegateObservable = null;
340
        }
341
    }
342

    
343
    public boolean allowWrite() {
344
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
345
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
346
            return false;
347
        }
348
        return this.provider.allowWrite();
349
    }
350

    
351
    public boolean canWriteGeometry(int geometryType) throws DataException {
352
        return this.provider.canWriteGeometry(geometryType, 0);
353
    }
354

    
355
    public DataServerExplorer getExplorer() throws ReadException,
356
        ValidateDataParametersException {
357
        return this.provider.getExplorer();
358
    }
359

    
360
    /*
361
     * public Metadata getMetadata() throws MetadataNotFoundException {
362
     * // TODO:
363
     * // Si el provider devuelbe null habria que ver de construir aqui
364
     * // los metadatos basicos, como el Envelope y el SRS.
365
     *
366
     * // TODO: Estando en edicion el Envelope deberia de
367
     * // actualizarse usando el spatialManager
368
     * return this.provider.getMetadata();
369
     * }
370
     */
371

    
372
    public Envelope getEnvelope() throws DataException {
373
        if (this.mode == MODE_FULLEDIT) {
374
                // Just in case another thread tries to write in the store
375
                synchronized (this) {
376
                        return this.spatialManager.getEnvelope();
377
                        }
378
        }
379
        if (hasDynValue(DataStore.METADATA_ENVELOPE)){
380
            return (Envelope)getDynValue(DataStore.METADATA_ENVELOPE);
381
        }
382
        return this.provider.getEnvelope();
383
    }
384

    
385
    /**
386
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
387
     */
388
    public IProjection getSRSDefaultGeometry() throws DataException {
389
        return this.getDefaultFeatureType().getDefaultSRS();
390
    }
391

    
392
    public FeatureSelection createDefaultFeatureSelection()
393
        throws DataException {
394
        return new DefaultFeatureSelection(this);
395
    }
396

    
397
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
398
        throws DataException {
399
        if (type.hasOID()) {
400
            return new DefaultFeatureProvider(type,
401
                this.provider.createNewOID());
402
        }
403
        return new DefaultFeatureProvider(type);
404
    }
405

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

    
440
        }
441

    
442
        if (evaluatedAttr.isEmpty()) {
443
            evaluatedAttr = null;
444
        }
445

    
446
        state.set("evaluatedAttributes", evaluatedAttr);
447
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
448

    
449
    }
450

    
451
    public void loadFromState(PersistentState state)
452
        throws PersistenceException {
453
        if (this.provider != null) {
454
            throw new PersistenceStoreAlreadyLoadedException(this.getName());
455
        }
456
        if (this.getManager() == null) {
457
            this.dataManager = (DefaultDataManager) DALLocator.getDataManager();
458
        }
459

    
460
        DataStoreParameters params =
461
            (DataStoreParameters) state.get("parameters");
462

    
463
        try {
464

    
465
            this.dataManager.intializeDataStore(this, params);
466
            this.selection = (FeatureSelection) state.get("selection");
467
            this.transforms =
468
                (DefaultFeatureStoreTransforms) state.get("transforms");
469
            Map evaluatedAttributes = (Map) state.get("evaluatedAttributes");
470
            if ((evaluatedAttributes != null) && !evaluatedAttributes.isEmpty()) {
471
                List attrs;
472
                Iterator iterEntries =
473
                    evaluatedAttributes.entrySet().iterator();
474
                Entry entry;
475
                while (iterEntries.hasNext()) {
476
                    entry = (Entry) iterEntries.next();
477
                    attrs = (List) entry.getValue();
478
                    if (attrs.isEmpty()) {
479
                        continue;
480
                    }
481
                    int fTypePos = -1;
482
                    DefaultFeatureType type = null;
483
                    for (int i = 0; i < featureTypes.size(); i++) {
484
                        type = (DefaultFeatureType) featureTypes.get(i);
485
                        if (type.getId().equals(entry.getKey())) {
486
                            fTypePos = i;
487
                            break;
488
                        }
489
                    }
490
                    if (fTypePos < 0) {
491
                        throw new PersistenceCantFindFeatureTypeException(
492
                            this.getName(), (String) entry.getKey());
493
                    }
494
                    DefaultEditableFeatureType eType =
495
                        (DefaultEditableFeatureType) type.getEditable();
496
                    Iterator iterAttr = attrs.iterator();
497
                    FeatureAttributeDescriptor attr;
498
                    while (iterAttr.hasNext()) {
499
                        attr = (FeatureAttributeDescriptor) iterAttr.next();
500
                        eType.addLike(attr);
501
                    }
502
                    featureTypes.set(fTypePos, eType.getNotEditableCopy());
503

    
504
                }
505

    
506
            }
507

    
508
            String defFTypeid = state.getString("defaultFeatureTypeId");
509
            FeatureType ftype = null;
510

    
511
            if (this.defaultFeatureType == null ||
512
                this.defaultFeatureType.getId() == null ||
513
                !this.defaultFeatureType.getId().equals(
514
                state.getString("defaultFeatureTypeId"))) {
515

    
516
                ftype = getFeatureType(defFTypeid);
517
                if (ftype == null) {
518
                        /*
519
                         * Un error en el m?todo de PostgresQL getName(), hace que 
520
                         * el nombre del featureType sea valor retornado por el getProviderName()
521
                         * De momento se pone este parche para apa?arlo y poder mantener compatibilidad
522
                         * con proyectos antiguos (2.1 y 2.2)
523
                         */
524
                        ftype = getFeatureType(provider.getName());
525
                        if(ftype == null){
526
                                throw new PersistenceCantFindDefaultFeatureTypeException(
527
                                                this.getName(), defFTypeid);
528
                        }
529
                }
530
                this.defaultFeatureType = ftype;
531
            }
532
            LOG.info("loadFromState() {} {}.", provider.getProviderName(), parameters.toString());
533

    
534
        } catch (InitializeException e) {
535
            throw new PersistenceException(e);
536
        } catch (DataException e) {
537
            throw new PersistenceException(e);
538
        }
539

    
540
    }
541

    
542
    public static void registerPersistenceDefinition() {
543
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
544
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
545
            DynStruct definition =
546
                manager.addDefinition(DefaultFeatureStore.class,
547
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
548
                        + " Persistent definition", null, null);
549
            definition.addDynFieldString("dataStoreName").setMandatory(true)
550
                .setPersistent(true);
551

    
552
            definition.addDynFieldObject("parameters")
553
                .setClassOfValue(DynObject.class).setMandatory(true)
554
                .setPersistent(true);
555

    
556
            definition.addDynFieldObject("selection")
557
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
558
                .setPersistent(true);
559

    
560
            definition.addDynFieldObject("transforms")
561
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
562
                .setMandatory(true).setPersistent(true);
563

    
564
            definition.addDynFieldMap("evaluatedAttributes")
565
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
566
                .setMandatory(false).setPersistent(true);
567

    
568
            definition.addDynFieldString("defaultFeatureTypeId")
569
                .setMandatory(true).setPersistent(true);
570
        }
571
    }
572

    
573
    public static void registerMetadataDefinition() throws MetadataException {
574
        MetadataManager manager = MetadataLocator.getMetadataManager();
575
        if (manager.getDefinition(METADATA_DEFINITION_NAME) == null) {
576
            DynStruct metadataDefinition =
577
                manager.addDefinition(METADATA_DEFINITION_NAME, null);
578
            metadataDefinition.extend(manager
579
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
580
        }
581
    }
582

    
583
    //
584
    // ====================================================================
585
    // Gestion de la seleccion
586
    //
587

    
588
    public void setSelection(DataSet selection) throws DataException {
589
        this.setSelection((FeatureSet) selection);
590
    }
591

    
592
    public DataSet createSelection() throws DataException {
593
        return createFeatureSelection();
594
    }
595

    
596
    public DataSet getSelection() throws DataException {
597
        return this.getFeatureSelection();
598
    }
599

    
600
    public void setSelection(FeatureSet selection) throws DataException {
601
        setSelection(selection, true);
602
    }
603

    
604
    /**
605
     * @see #setSelection(FeatureSet)
606
     * @param undoable
607
     *            if the action must be undoable
608
     */
609
    public void setSelection(FeatureSet selection, boolean undoable)
610
        throws DataException {
611
        if (selection == null) {
612
            if (undoable) {
613
                throw new SelectionNotAllowedException(getName());
614
            }
615

    
616
        } else {
617
            if (selection.equals(this.selection)) {
618
                return;
619
            }
620
            if (!selection.isFromStore(this)) {
621
                throw new SelectionNotAllowedException(getName());
622
            }
623
        }
624

    
625
        if (this.selection != null) {
626
            this.selection.deleteObserver(this);
627
        }
628
        if (selection == null) {
629
            if (this.selection != null) {
630
                this.selection.dispose();
631
            }
632
            this.selection = null;
633
            return;
634
        }
635
        if (selection instanceof FeatureSelection) {
636
            if (undoable && isEditing()) {
637
                commands.selectionSet(this, this.selection,
638
                    (FeatureSelection) selection);
639
            }
640
            if (this.selection != null) {
641
                this.selection.dispose();
642
            }
643
            this.selection = (FeatureSelection) selection;
644
        } else {
645
            if (undoable && isEditing()) {
646
                commands.startComplex("_selectionSet");
647
            }
648
            if (selection instanceof DefaultFeatureSelection) {
649
                DefaultFeatureSelection defSelection =
650
                    (DefaultFeatureSelection) selection;
651
                defSelection.deselectAll(undoable);
652
                defSelection.select(selection, undoable);
653
            } else {
654
                this.selection.deselectAll();
655
                this.selection.select(selection);
656
            }
657
            if (undoable && isEditing()) {
658
                commands.endComplex();
659
            }
660
        }
661
        this.selection.addObserver(this);
662

    
663
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
664
    }
665

    
666
    public FeatureSelection createFeatureSelection() throws DataException {
667
        return this.provider.createFeatureSelection();
668
    }
669

    
670
    public FeatureSelection getFeatureSelection() throws DataException {
671
        if (selection == null) {
672
            this.selection = createFeatureSelection();
673
            this.selection.addObserver(this);
674
        }
675
        return selection;
676
    }
677

    
678
    //
679
    // ====================================================================
680
    // Gestion de notificaciones
681
    //
682

    
683
    public void notifyChange(String notification) {
684
        if (delegateObservable != null) {
685
            notifyChange(new DefaultFeatureStoreNotification(this, notification));
686
        }
687

    
688
    }
689

    
690
    public void notifyChange(String notification, FeatureProvider data) {
691
        try {
692
            notifyChange(notification, createFeature(data));
693
        } catch (DataException ex) {
694
            LOG.error("Error notifying about the notification: " + notification
695
                + ", with the data: " + data, ex);
696
        }
697
    }
698

    
699
    public void notifyChange(String notification, Feature feature) {
700
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
701
            feature));
702
    }
703

    
704
    public void notifyChange(String notification, Command command) {
705
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
706
            command));
707
    }
708

    
709
    public void notifyChange(String notification, EditableFeatureType type) {
710
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
711
            type));
712
    }
713

    
714
    public void notifyChange(FeatureStoreNotification storeNotification) {
715
        delegateObservable.notifyObservers(storeNotification);
716
    }
717

    
718
    public void notifyChange(String notification, Resource resource) {
719
        notifyChange(new DefaultFeatureStoreNotification(this,
720
            DataStoreNotification.RESOURCE_CHANGED));
721
    }
722

    
723
    //
724
    // ====================================================================
725
    // Gestion de bloqueos
726
    //
727

    
728
    public boolean isLocksSupported() {
729
        return this.provider.isLocksSupported();
730
    }
731

    
732
    public FeatureLocks getLocks() throws DataException {
733
        if (!this.provider.isLocksSupported()) {
734
            LOG.warn("Locks not supported");
735
            return null;
736
        }
737
        if (locks == null) {
738
            this.locks = this.provider.createFeatureLocks();
739
        }
740
        return locks;
741
    }
742

    
743
    //
744
    // ====================================================================
745
    // Interface Observable
746
    //
747

    
748
    public void disableNotifications() {
749
        this.delegateObservable.disableNotifications();
750

    
751
    }
752

    
753
    public void enableNotifications() {
754
        this.delegateObservable.enableNotifications();
755
    }
756

    
757
    public void beginComplexNotification() {
758
        this.delegateObservable.beginComplexNotification();
759

    
760
    }
761

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

    
765
    }
766

    
767
    public void addObserver(Observer observer) {
768
        if (delegateObservable != null) {
769
            this.delegateObservable.addObserver(observer);
770
        }
771
    }
772

    
773
    public void deleteObserver(Observer observer) {
774
        if (delegateObservable != null) {
775
            this.delegateObservable.deleteObserver(observer);
776
        }
777
    }
778

    
779
    public void deleteObservers() {
780
        this.delegateObservable.deleteObservers();
781

    
782
    }
783

    
784
    //
785
    // ====================================================================
786
    // Interface Observer
787
    //
788
    // Usado para observar:
789
    // - su seleccion
790
    // - sus bloqueos
791
    // - sus recursos
792
    //
793

    
794
    public void update(Observable observable, Object notification) {
795
        if (observable instanceof FeatureSet) {
796
            if (observable == this.selection) {
797
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
798
            } else
799
                if (observable == this.locks) {
800
                    this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
801
                }
802

    
803
        } else
804
            if (observable instanceof FeatureStoreProvider) {
805
                if (observable == this.provider) {
806

    
807
                }
808

    
809
            }
810
    }
811

    
812
    //
813
    // ====================================================================
814
    // Edicion
815
    //
816

    
817
    private void newVersionOfUpdate() {
818
        this.versionOfUpdate++;
819
    }
820

    
821
    private long currentVersionOfUpdate() {
822
        return this.versionOfUpdate;
823
    }
824

    
825
    private void checkInEditingMode() throws NeedEditingModeException {
826
        if (mode != MODE_FULLEDIT) {
827
            throw new NeedEditingModeException(this.getName());
828
        }
829
    }
830

    
831
    private void checkNotInAppendMode() throws IllegalStateException {
832
        if (mode == MODE_APPEND) {
833
                        throw new IllegalStateException("Error: store "
834
                                        + this.getFullName() + " is in append mode");
835
        }
836
    }
837

    
838
    private void checkIsOwnFeature(Feature feature)
839
        throws IllegalFeatureException {
840
        if (((DefaultFeature) feature).getStore() != this) {
841
            throw new IllegalFeatureException(this.getName());
842
        }
843
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
844
        // fixFeatureType((DefaultFeatureType) feature.getType());
845
    }
846

    
847
    private void exitEditingMode() {
848
        if (commands != null) {
849
            commands.clear();
850
            commands = null;
851
        }
852

    
853
        if (featureTypeManager != null) {
854
            featureTypeManager.dispose();
855
            featureTypeManager = null;
856

    
857
        }
858

    
859
        // TODO implementar un dispose para estos dos
860
        featureManager = null;
861
        spatialManager = null;
862

    
863
        featureCount = null;
864

    
865
        mode = MODE_QUERY;
866
        hasStrongChanges = true; // Lo deja a true por si las moscas
867
        hasInserts = true;
868
    }
869

    
870
    synchronized public void edit() throws DataException {
871
        edit(MODE_FULLEDIT);
872
    }
873

    
874
    synchronized public void edit(int mode) throws DataException {
875
        LOG.debug("Starting editing in mode: {}", new Integer(mode));
876
        try {
877
            if (this.mode != MODE_QUERY) {
878
                throw new AlreadyEditingException(this.getName());
879
            }
880
            if (!this.provider.supportsAppendMode()) {
881
                mode = MODE_FULLEDIT;
882
            }
883
            switch (mode) {
884
            case MODE_QUERY:
885
                throw new IllegalStateException(this.getName());
886

    
887
            case MODE_FULLEDIT:
888
                if (!this.transforms.isEmpty()) {
889
                    throw new IllegalStateException(this.getName());
890
                }
891
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
892
                invalidateIndexes();
893
                featureManager =
894
                    new FeatureManager(new MemoryExpansionAdapter());
895
                featureTypeManager =
896
                    new FeatureTypeManager(this, new MemoryExpansionAdapter());
897
                spatialManager =
898
                    new SpatialManager(this, provider.getEnvelope());
899

    
900
                commands =
901
                    new DefaultFeatureCommandsStack(this, featureManager,
902
                        spatialManager, featureTypeManager);
903
                this.mode = MODE_FULLEDIT;
904
                hasStrongChanges = false;
905
                hasInserts = false;
906
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
907
                break;
908
            case MODE_APPEND:
909
                if (!this.transforms.isEmpty()) {
910
                    throw new IllegalStateException(this.getName());
911
                }
912
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
913
                invalidateIndexes();
914
                this.provider.beginAppend();
915
                this.mode = MODE_APPEND;
916
                hasInserts = false;
917
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
918
                break;
919
            }
920
        } catch (Exception e) {
921
            throw new StoreEditException(e, this.getName());
922
        }
923
    }
924

    
925
    private void invalidateIndexes() {
926
        setIndexesValidStatus(false);
927
    }
928

    
929
    private void setIndexesValidStatus(boolean valid) {
930
        FeatureIndexes indexes = getIndexes();
931
        LOG.debug("Setting the store indexes to valid status {}: {}", (valid
932
            ? Boolean.TRUE : Boolean.FALSE), indexes);
933
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
934
            FeatureIndex index = (FeatureIndex) iterator.next();
935
            if (index instanceof FeatureIndexProviderServices) {
936
                FeatureIndexProviderServices indexServices =
937
                    (FeatureIndexProviderServices) index;
938
                indexServices.setValid(valid);
939
            }
940
        }
941
    }
942

    
943
    private void updateIndexes() throws FeatureIndexException {
944
        FeatureIndexes indexes = getIndexes();
945
        LOG.debug("Refilling indexes: {}", indexes);
946
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
947
            FeatureIndex index = (FeatureIndex) iterator.next();
948
            if (index instanceof FeatureIndexProviderServices) {
949
                FeatureIndexProviderServices indexServices =
950
                    (FeatureIndexProviderServices) index;
951
                indexServices.fill(true, null);
952
            }
953
        }
954
    }
955

    
956
    private void waitForIndexes() {
957
        FeatureIndexes indexes = getIndexes();
958
        LOG.debug("Waiting for indexes to finish filling: {}", indexes);
959
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
960
            FeatureIndex index = (FeatureIndex) iterator.next();
961
            if (index instanceof FeatureIndexProviderServices) {
962
                FeatureIndexProviderServices indexServices =
963
                    (FeatureIndexProviderServices) index;
964
                indexServices.waitForIndex();
965
            }
966
        }
967
    }
968

    
969
    private void disposeIndexes() {
970
        FeatureIndexes indexes = getIndexes();
971
        LOG.debug("Disposing indexes: {}", indexes);
972
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
973
            FeatureIndex index = (FeatureIndex) iterator.next();
974
            if (index instanceof FeatureIndexProviderServices) {
975
                FeatureIndexProviderServices indexServices =
976
                    (FeatureIndexProviderServices) index;
977
                indexServices.dispose();
978
            }
979
        }
980
    }
981

    
982
    public boolean isEditing() {
983
        return mode == MODE_FULLEDIT;
984
    }
985

    
986
    public boolean isAppending() {
987
        return mode == MODE_APPEND;
988
    }
989

    
990
    synchronized public void update(EditableFeatureType type)
991
        throws DataException {
992
        try {
993
            checkInEditingMode();
994
            if (type == null) {
995
                throw new NullFeatureTypeException(getName());
996
            }
997
            // FIXME: Comprobar que es un featureType aceptable.
998
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
999
            newVersionOfUpdate();
1000

    
1001
            FeatureType oldt = type.getSource().getCopy();
1002
            FeatureType newt = type.getCopy();
1003
            commands.update(newt, oldt);
1004

    
1005
            if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
1006
                hasStrongChanges = true;
1007
            }
1008
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1009
        } catch (Exception e) {
1010
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1011
        }
1012
    }
1013

    
1014
    public void delete(Feature feature) throws DataException {
1015
        this.commands.delete(feature);
1016
    }
1017

    
1018
    synchronized public void doDelete(Feature feature) throws DataException {
1019
        try {
1020
            checkInEditingMode();
1021
            checkIsOwnFeature(feature);
1022
            if (feature instanceof EditableFeature) {
1023
                throw new StoreDeleteEditableFeatureException(getName());
1024
            }
1025
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1026

    
1027
            //Update the featureManager and the spatialManager
1028
            featureManager.delete(feature.getReference());
1029
            spatialManager.deleteFeature(feature);
1030

    
1031
            newVersionOfUpdate();
1032
            hasStrongChanges = true;
1033
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1034
        } catch (Exception e) {
1035
            throw new StoreDeleteFeatureException(e, this.getName());
1036
        }
1037
    }
1038

    
1039
    private static EditableFeature lastChangedFeature = null;
1040

    
1041
    public synchronized void insert(EditableFeature feature)
1042
        throws DataException {
1043
        LOG.debug("In editing mode {}, insert feature: {}", new Integer(mode),
1044
            feature);
1045
        try {
1046
            switch (mode) {
1047
            case MODE_QUERY:
1048
                throw new NeedEditingModeException(this.getName());
1049

    
1050
            case MODE_APPEND:
1051
                checkIsOwnFeature(feature);
1052
                if (feature.getSource() != null) {
1053
                    throw new NoNewFeatureInsertException(this.getName());
1054
                }
1055
                this.featureCount = null;
1056
                notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1057
                feature.validate(Feature.UPDATE);
1058
                provider.append(((DefaultEditableFeature) feature).getData());
1059
                hasStrongChanges = true;
1060
                hasInserts = true;
1061
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1062
                break;
1063

    
1064
            case MODE_FULLEDIT:
1065
                if (feature.getSource() != null) {
1066
                    throw new NoNewFeatureInsertException(this.getName());
1067
                }
1068
                commands.insert(feature);
1069
            }
1070
        } catch (Exception e) {
1071
            throw new StoreInsertFeatureException(e, this.getName());
1072
        }
1073
    }
1074

    
1075
    synchronized public void doInsert(EditableFeature feature)
1076
        throws DataException {
1077
        checkIsOwnFeature(feature);
1078

    
1079
        waitForIndexes();
1080

    
1081
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1082
        newVersionOfUpdate();
1083
        if ((lastChangedFeature == null)
1084
            || (lastChangedFeature.getSource() != feature.getSource())) {
1085
            lastChangedFeature = feature;
1086
            feature.validate(Feature.UPDATE);
1087
            lastChangedFeature = null;
1088
        }
1089
        //Update the featureManager and the spatialManager
1090
        ((DefaultEditableFeature) feature).setInserted(true);
1091
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1092

    
1093

    
1094
        featureManager.add(newFeature);
1095
        spatialManager.insertFeature(newFeature);
1096

    
1097
        hasStrongChanges = true;
1098
        hasInserts = true;
1099
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1100
    }
1101

    
1102
    public void update(EditableFeature feature)
1103
    throws DataException {
1104
        if ((feature).getSource() == null) {
1105
            insert(feature);
1106
            return;
1107
        }
1108
        commands.update(feature, feature.getSource());
1109
    }
1110

    
1111
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1112
        throws DataException {
1113
        try {
1114
            checkInEditingMode();
1115
            checkIsOwnFeature(feature);
1116
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature);
1117
            newVersionOfUpdate();
1118
            if ((lastChangedFeature == null)
1119
                || (lastChangedFeature.getSource() != feature.getSource())) {
1120
                lastChangedFeature = feature;
1121
                feature.validate(Feature.UPDATE);
1122
                lastChangedFeature = null;
1123
            }
1124

    
1125
            //Update the featureManager and the spatialManager
1126
            Feature newf = feature.getNotEditableCopy();
1127
            featureManager.update(newf, oldFeature);
1128
            spatialManager.updateFeature(newf, oldFeature);
1129

    
1130
            hasStrongChanges = true;
1131
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1132
        } catch (Exception e) {
1133
            throw new StoreUpdateFeatureException(e, this.getName());
1134
        }
1135
    }
1136

    
1137
    synchronized public void redo() throws RedoException {
1138
        Command redo = commands.getNextRedoCommand();
1139
        try {
1140
            checkInEditingMode();
1141
        } catch (NeedEditingModeException ex) {
1142
            throw new RedoException(redo, ex);
1143
        }
1144
        notifyChange(FeatureStoreNotification.BEFORE_REDO, redo);
1145
        newVersionOfUpdate();
1146
        commands.redo();
1147
        hasStrongChanges = true;
1148
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1149
    }
1150

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

    
1165
    public List getRedoInfos() {
1166
        if (isEditing() && (commands != null)) {
1167
            return commands.getRedoInfos();
1168
        } else {
1169
            return null;
1170
        }
1171
    }
1172

    
1173
    public List getUndoInfos() {
1174
        if (isEditing() && (commands != null)) {
1175
            return commands.getUndoInfos();
1176
        } else {
1177
            return null;
1178
        }
1179
    }
1180

    
1181
    public synchronized FeatureCommandsStack getCommandsStack()
1182
        throws DataException {
1183
        checkInEditingMode();
1184
        return commands;
1185
    }
1186

    
1187
    synchronized public void cancelEditing() throws DataException {
1188
        spatialManager.cancelModifies();
1189
        try {
1190
            checkInEditingMode();
1191

    
1192
            boolean clearSelection = this.hasStrongChanges;
1193
            if (this.selection instanceof FeatureReferenceSelection) {
1194
                clearSelection = this.hasInserts;
1195
            }
1196
            notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1197
            exitEditingMode();
1198
            if (clearSelection) {
1199
                ((FeatureSelection) this.getSelection()).deselectAll();
1200
            }
1201
            updateIndexes();
1202
            notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1203
        } catch (Exception e) {
1204
            throw new StoreCancelEditingException(e, this.getName());
1205
        }
1206
    }
1207

    
1208
    synchronized public void finishEditing() throws DataException {
1209
        LOG.debug("finish editing of mode: {}", new Integer(mode));
1210
        try {
1211

    
1212
            /*
1213
             * Selection needs to be cleared when editing stops
1214
             * to prevent conflicts with selection remaining from
1215
             * editing mode.
1216
             */
1217
//            ((FeatureSelection) this.getSelection()).deselectAll();
1218

    
1219
            switch (mode) {
1220
            case MODE_QUERY:
1221
                throw new NeedEditingModeException(this.getName());
1222

    
1223
            case MODE_APPEND:
1224
                ((FeatureSelection) this.getSelection()).deselectAll();
1225
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1226
                provider.endAppend();
1227
                exitEditingMode();
1228
                updateIndexes();
1229
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1230
                break;
1231

    
1232
            case MODE_FULLEDIT:
1233
                if (hasStrongChanges && !this.allowWrite()) {
1234
                    throw new WriteNotAllowedException(getName());
1235
                }
1236

    
1237
                if(featureManager.isSelectionCompromised()) {
1238
                    ((FeatureSelection) this.getSelection()).deselectAll();
1239
                };
1240

    
1241
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1242
                if (hasStrongChanges) {
1243
                    validateFeatures(Feature.FINISH_EDITING);
1244

    
1245
                    /*
1246
                     * This will throw a PerformEditingExceptionif the provider
1247
                     * does not accept the changes (for example, an invalid field name)
1248
                     */
1249
                    provider.performChanges(featureManager.getDeleted(),
1250
                        featureManager.getInserted(),
1251
                        featureManager.getUpdated(),
1252
                        featureTypeManager.getFeatureTypesChanged());
1253
                }
1254
                exitEditingMode();
1255
                updateIndexes();
1256
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1257
                break;
1258
            }
1259
        } catch (PerformEditingException pee) {
1260
            throw new WriteException(provider.getSourceId().toString(), pee);
1261
        } catch (Exception e) {
1262
            throw new FinishEditingException(e);
1263
        }
1264
    }
1265

    
1266
    /**
1267
     * Save changes in the provider without leaving the edit mode.
1268
     * Do not call observers to communicate a change of ediding mode.
1269
     * The operation's history is eliminated to prevent inconsistencies
1270
     * in the data.
1271
     *
1272
     * @throws DataException
1273
     */
1274
    synchronized public void commitChanges() throws DataException {
1275
      LOG.debug("commitChanges of mode: {}", new Integer(mode));
1276
      if( !canCommitChanges() ) {
1277
              throw new WriteNotAllowedException(getName());
1278
      }
1279
      try {
1280
        switch (mode) {
1281
        case MODE_QUERY:
1282
          throw new NeedEditingModeException(this.getName());
1283

    
1284
        case MODE_APPEND:
1285
          this.provider.endAppend();
1286
          exitEditingMode();
1287
          invalidateIndexes();
1288
          this.provider.beginAppend();
1289
          hasInserts = false;
1290
          break;
1291

    
1292
        case MODE_FULLEDIT:
1293
          if (hasStrongChanges && !this.allowWrite()) {
1294
            throw new WriteNotAllowedException(getName());
1295
          }
1296
          if (hasStrongChanges) {
1297
            validateFeatures(Feature.FINISH_EDITING);
1298
            provider.performChanges(featureManager.getDeleted(),
1299
              featureManager.getInserted(),
1300
              featureManager.getUpdated(),
1301
              featureTypeManager.getFeatureTypesChanged());
1302
          }
1303
          invalidateIndexes();
1304
          featureManager =
1305
            new FeatureManager(new MemoryExpansionAdapter());
1306
          featureTypeManager =
1307
            new FeatureTypeManager(this, new MemoryExpansionAdapter());
1308
          spatialManager =
1309
            new SpatialManager(this, provider.getEnvelope());
1310

    
1311
          commands =
1312
            new DefaultFeatureCommandsStack(this, featureManager,
1313
              spatialManager, featureTypeManager);
1314
          featureCount = null;
1315
          hasStrongChanges = false;
1316
          hasInserts = false;
1317
          break;
1318
        }
1319
      } catch (Exception e) {
1320
        throw new FinishEditingException(e);
1321
      }
1322
    }
1323

    
1324
    synchronized public boolean canCommitChanges() throws DataException {
1325
        if ( !this.allowWrite()) {
1326
                return false;
1327
        }
1328
            switch (mode) {
1329
            default:
1330
        case MODE_QUERY:
1331
                return false;
1332

    
1333
        case MODE_APPEND:
1334
                return true;
1335

    
1336
        case MODE_FULLEDIT:
1337
            List types = this.getFeatureTypes();
1338
            for( int i=0; i<types.size(); i++ ) {
1339
                    Object type = types.get(i);
1340
                    if( type instanceof DefaultEditableFeatureType ) {
1341
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1342
                                    return false;
1343
                            }
1344
                    }
1345
            }
1346
            return true;
1347
            }
1348
    }
1349

    
1350
    public void beginEditingGroup(String description)
1351
        throws NeedEditingModeException {
1352
        checkInEditingMode();
1353
        commands.startComplex(description);
1354
    }
1355

    
1356
    public void endEditingGroup() throws NeedEditingModeException {
1357
        checkInEditingMode();
1358
        commands.endComplex();
1359
    }
1360

    
1361
    public boolean isAppendModeSupported() {
1362
        return this.provider.supportsAppendMode();
1363
    }
1364

    
1365
    public void export(DataServerExplorer explorer, String provider,
1366
        NewFeatureStoreParameters params) throws DataException {
1367

    
1368
        if (this.getFeatureTypes().size() != 1) {
1369
            throw new NotYetImplemented(
1370
                "export whith more than one type not yet implemented");
1371
        }
1372
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1373
        FeatureStore target = null;
1374
        FeatureSet features = null;
1375
        DisposableIterator iterator = null;
1376
        try {
1377
            FeatureType type = this.getDefaultFeatureType();
1378
            if ((params.getDefaultFeatureType() == null)
1379
                || (params.getDefaultFeatureType().size() == 0)) {
1380
                params.setDefaultFeatureType(type.getEditable());
1381

    
1382
            }
1383
            explorer.add(provider, params, true);
1384

    
1385
            DataManager manager = DALLocator.getDataManager();
1386
            target = (FeatureStore) manager.openStore(provider, params);
1387
            FeatureType targetType = target.getDefaultFeatureType();
1388

    
1389
            target.edit(MODE_APPEND);
1390
            FeatureAttributeDescriptor[] pk = type.getPrimaryKey();
1391
            if (featureSelection.getSize() > 0) {
1392
                features = this.getFeatureSelection();
1393
            } else {
1394
                if ((pk != null) && (pk.length > 0)) {
1395
                    FeatureQuery query = createFeatureQuery();
1396
                    for (int i = 0; i < pk.length; i++) {
1397
                        query.getOrder().add(pk[i].getName(), true);
1398
                    }
1399
                    features = this.getFeatureSet(query);
1400
                } else {
1401
                    features = this.getFeatureSet();
1402
                }
1403
            }
1404
            iterator = features.fastIterator();
1405
            while (iterator.hasNext()) {
1406
                DefaultFeature feature = (DefaultFeature) iterator.next();
1407
                target.insert(target.createNewFeature(targetType, feature));
1408
            }
1409
            target.finishEditing();
1410
            target.dispose();
1411
        } catch (Exception e) {
1412
            throw new DataExportException(e, params.toString());
1413
        } finally {
1414
            dispose(iterator);
1415
            dispose(features);
1416
            dispose(target);
1417
        }
1418
    }
1419

    
1420
    //
1421
    // ====================================================================
1422
    // Obtencion de datos
1423
    // getDataCollection, getFeatureCollection
1424
    //
1425

    
1426
    public DataSet getDataSet() throws DataException {
1427
        checkNotInAppendMode();
1428
        FeatureQuery query =
1429
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1430
        return new DefaultFeatureSet(this, query);
1431
    }
1432

    
1433
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1434
        checkNotInAppendMode();
1435
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1436
    }
1437

    
1438
    public void getDataSet(Observer observer) throws DataException {
1439
        checkNotInAppendMode();
1440
        this.getFeatureSet(null, observer);
1441
    }
1442

    
1443
    public void getDataSet(DataQuery dataQuery, Observer observer)
1444
        throws DataException {
1445
        checkNotInAppendMode();
1446
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1447
    }
1448

    
1449
    @Override
1450
    public FeatureSet getFeatureSet() throws DataException {
1451
        return this.getFeatureSet((FeatureQuery)null);
1452
    }
1453

    
1454
    @Override
1455
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1456
        throws DataException {
1457
        checkNotInAppendMode();
1458
        if( featureQuery==null ) {
1459
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1460
        }
1461
        return new DefaultFeatureSet(this, featureQuery);
1462
    }
1463

    
1464
    @Override
1465
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
1466
        try {
1467
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
1468
            return pager.asList();
1469
        } catch (BaseException ex) {
1470
            throw new RuntimeException("Can't create the list of features.", ex);
1471
        }
1472
    }
1473
    
1474
    public void accept(Visitor visitor) throws BaseException {
1475
        FeatureSet set = getFeatureSet();
1476
        try {
1477
            set.accept(visitor);
1478
        } finally {
1479
            set.dispose();
1480
        }
1481
    }
1482

    
1483
    public void accept(Visitor visitor, DataQuery dataQuery)
1484
        throws BaseException {
1485
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
1486
        try {
1487
            set.accept(visitor);
1488
        } finally {
1489
            set.dispose();
1490
        }
1491
    }
1492

    
1493
    public FeatureType getFeatureType(FeatureQuery featureQuery)
1494
        throws DataException {
1495
        DefaultFeatureType fType =
1496
            (DefaultFeatureType) this.getFeatureType(featureQuery
1497
                .getFeatureTypeId());
1498
        if( featureQuery.hasAttributeNames() || featureQuery.hasConstantsAttributeNames() ) {
1499
            return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames() );
1500
        }
1501
        return fType;
1502
    }
1503

    
1504
    public void getFeatureSet(Observer observer) throws DataException {
1505
        checkNotInAppendMode();
1506
        this.getFeatureSet(null, observer);
1507
    }
1508

    
1509
    public void getFeatureSet(FeatureQuery query, Observer observer)
1510
        throws DataException {
1511
        class LoadInBackGround implements Runnable {
1512

    
1513
            private FeatureStore store;
1514
            private FeatureQuery query;
1515
            private Observer observer;
1516

    
1517
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
1518
                Observer observer) {
1519
                this.store = store;
1520
                this.query = query;
1521
                this.observer = observer;
1522
            }
1523

    
1524
            void notify(FeatureStoreNotification theNotification) {
1525
                observer.update(store, theNotification);
1526
                return;
1527
            }
1528

    
1529
            public void run() {
1530
                FeatureSet set = null;
1531
                try {
1532
                    set = store.getFeatureSet(query);
1533
                    notify(new DefaultFeatureStoreNotification(store,
1534
                        FeatureStoreNotification.LOAD_FINISHED, set));
1535
                } catch (Exception e) {
1536
                    notify(new DefaultFeatureStoreNotification(store,
1537
                        FeatureStoreNotification.LOAD_FINISHED, e));
1538
                } finally {
1539
                    dispose(set);
1540
                }
1541
            }
1542
        }
1543

    
1544
        checkNotInAppendMode();
1545
        if (query == null) {
1546
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
1547
        }
1548
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
1549
        Thread thread = new Thread(task, "Load Feature Set in background");
1550
        thread.start();
1551
    }
1552

    
1553
    public Feature getFeatureByReference(FeatureReference reference)
1554
        throws DataException {
1555
        checkNotInAppendMode();
1556
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
1557
        FeatureType featureType;
1558
        if (ref.getFeatureTypeId() == null) {
1559
            featureType = this.getDefaultFeatureType();
1560
        } else {
1561
            featureType = this.getFeatureType(ref.getFeatureTypeId());
1562
        }
1563
        return this.getFeatureByReference(reference, featureType);
1564
    }
1565

    
1566
    public Feature getFeatureByReference(FeatureReference reference,
1567
        FeatureType featureType) throws DataException {
1568
        checkNotInAppendMode();
1569
        featureType = fixFeatureType((DefaultFeatureType) featureType);
1570
        if (this.mode == MODE_FULLEDIT) {
1571
            Feature f = featureManager.get(reference, this, featureType);
1572
            if (f != null) {
1573
                return f;
1574
            }
1575
        }
1576

    
1577
        FeatureType sourceFeatureType = featureType;
1578
        if (!this.transforms.isEmpty()) {
1579
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
1580
        }
1581
        // TODO comprobar que el id es de este store
1582

    
1583
        DefaultFeature feature =
1584
            new DefaultFeature(this,
1585
                this.provider.getFeatureProviderByReference(
1586
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
1587

    
1588
        if (!this.transforms.isEmpty()) {
1589
            return this.transforms.applyTransform(feature, featureType);
1590
        }
1591
        return feature;
1592
    }
1593

    
1594
    //
1595
    // ====================================================================
1596
    // Gestion de features
1597
    //
1598

    
1599
    private FeatureType fixFeatureType(DefaultFeatureType type)
1600
        throws DataException {
1601
        FeatureType original = this.getDefaultFeatureType();
1602

    
1603
        if ((type == null) || type.equals(original)) {
1604
            return original;
1605
        } else {
1606
            if (!type.isSubtypeOf(original)) {
1607
                Iterator iter = this.getFeatureTypes().iterator();
1608
                FeatureType tmpType;
1609
                boolean found = false;
1610
                while (iter.hasNext()) {
1611
                    tmpType = (FeatureType) iter.next();
1612
                    if (type.equals(tmpType)) {
1613
                        return type;
1614

    
1615
                    } else
1616
                        if (type.isSubtypeOf(tmpType)) {
1617
                            found = true;
1618
                            original = tmpType;
1619
                            break;
1620
                        }
1621

    
1622
                }
1623
                if (!found) {
1624
                    throw new IllegalFeatureTypeException(getName());
1625
                }
1626
            }
1627
        }
1628

    
1629
        // Checks that type has all fields of pk
1630
        // else add the missing attributes at the end.
1631
        if (!original.hasOID()) {
1632
            // Gets original pk attributes
1633
            DefaultEditableFeatureType edOriginal =
1634
                (DefaultEditableFeatureType) original.getEditable();
1635
            FeatureAttributeDescriptor orgAttr;
1636
            Iterator edOriginalIter = edOriginal.iterator();
1637
            while (edOriginalIter.hasNext()) {
1638
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1639
                if (!orgAttr.isPrimaryKey()) {
1640
                    edOriginalIter.remove();
1641
                }
1642
            }
1643

    
1644
            // Checks if all pk attributes are in type
1645
            Iterator typeIterator;
1646
            edOriginalIter = edOriginal.iterator();
1647
            FeatureAttributeDescriptor attr;
1648
            while (edOriginalIter.hasNext()) {
1649
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1650
                typeIterator = type.iterator();
1651
                while (typeIterator.hasNext()) {
1652
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
1653
                    if (attr.getName().equals(orgAttr.getName())) {
1654
                        edOriginalIter.remove();
1655
                        break;
1656
                    }
1657
                }
1658
            }
1659

    
1660
            // add missing pk attributes if any
1661
            if (edOriginal.size() > 0) {
1662
                boolean isEditable = type instanceof DefaultEditableFeatureType;
1663
                DefaultEditableFeatureType edType =
1664
                    (DefaultEditableFeatureType) original.getEditable();
1665
                edType.clear();
1666
                edType.addAll(type);
1667
                edType.addAll(edOriginal);
1668
                if (!isEditable) {
1669
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
1670
                }
1671
            }
1672

    
1673
        }
1674

    
1675
        return type;
1676
    }
1677

    
1678
    public void validateFeatures(int mode) throws DataException {
1679
        FeatureSet collection = null;
1680
        DisposableIterator iter = null;
1681
        try {
1682
            checkNotInAppendMode();
1683
            collection = this.getFeatureSet();
1684
            iter = collection.fastIterator();
1685
            long previousVersionOfUpdate = currentVersionOfUpdate();
1686
            while (iter.hasNext()) {
1687
                ((DefaultFeature) iter.next()).validate(mode);
1688
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
1689
                    throw new ConcurrentDataModificationException(getName());
1690
                }
1691
            }
1692
        } catch (Exception e) {
1693
            throw new ValidateFeaturesException(e, getName());
1694
        } finally {
1695
            dispose(iter);
1696
            dispose(collection);
1697
        }
1698
    }
1699

    
1700
    public FeatureType getDefaultFeatureType() throws DataException {
1701
        try {
1702

    
1703
            if (isEditing()) {
1704
                FeatureType auxFeatureType =
1705
                    featureTypeManager.getType(defaultFeatureType.getId());
1706
                if (auxFeatureType != null) {
1707
                    return avoidEditable(auxFeatureType);
1708
                }
1709
            }
1710
            FeatureType type = this.transforms.getDefaultFeatureType();
1711
            if (type != null) {
1712
                return avoidEditable(type);
1713
            }
1714

    
1715
            return avoidEditable(defaultFeatureType);
1716

    
1717
        } catch (Exception e) {
1718
            throw new GetFeatureTypeException(e, getName());
1719
        }
1720
    }
1721

    
1722
    private FeatureType avoidEditable(FeatureType ft) {
1723
        if (ft instanceof EditableFeatureType) {
1724
            return ((EditableFeatureType) ft).getNotEditableCopy();
1725
        } else {
1726
            return ft;
1727
        }
1728
    }
1729

    
1730
    public FeatureType getFeatureType(String featureTypeId)
1731
        throws DataException {
1732
        if (featureTypeId == null) {
1733
            return this.getDefaultFeatureType();
1734
        }
1735
        try {
1736
            if (isEditing()) {
1737
                FeatureType auxFeatureType =
1738
                    featureTypeManager.getType(featureTypeId);
1739
                if (auxFeatureType != null) {
1740
                    return auxFeatureType;
1741
                }
1742
            }
1743
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
1744
            if (type != null) {
1745
                return type;
1746
            }
1747
            Iterator iter = this.featureTypes.iterator();
1748
            while (iter.hasNext()) {
1749
                type = (FeatureType) iter.next();
1750
                if (type.getId().equals(featureTypeId)) {
1751
                    return type;
1752
                }
1753
            }
1754
            return null;
1755
        } catch (Exception e) {
1756
            throw new GetFeatureTypeException(e, getName());
1757
        }
1758
    }
1759

    
1760
    public FeatureType getProviderDefaultFeatureType() {
1761
        return defaultFeatureType;
1762
    }
1763

    
1764
    public List getFeatureTypes() throws DataException {
1765
        try {
1766
            List types;
1767
            if (isEditing()) {
1768
                types = new ArrayList();
1769
                Iterator it = featureTypes.iterator();
1770
                while (it.hasNext()) {
1771
                    FeatureType type = (FeatureType) it.next();
1772
                    FeatureType typeaux =
1773
                        featureTypeManager.getType(type.getId());
1774
                    if (typeaux != null) {
1775
                        types.add(typeaux);
1776
                    } else {
1777
                        types.add(type);
1778
                    }
1779
                }
1780
                it = featureTypeManager.newsIterator();
1781
                while (it.hasNext()) {
1782
                    FeatureType type = (FeatureType) it.next();
1783
                    types.add(type);
1784
                }
1785
            } else {
1786
                types = this.transforms.getFeatureTypes();
1787
                if (types == null) {
1788
                    types = featureTypes;
1789
                }
1790
            }
1791
            return Collections.unmodifiableList(types);
1792
        } catch (Exception e) {
1793
            throw new GetFeatureTypeException(e, getName());
1794
        }
1795
    }
1796

    
1797
    public List getProviderFeatureTypes() throws DataException {
1798
        return Collections.unmodifiableList(this.featureTypes);
1799
    }
1800

    
1801
    public Feature createFeature(FeatureProvider data) throws DataException {
1802
        DefaultFeature feature = new DefaultFeature(this, data);
1803
        return feature;
1804
    }
1805

    
1806
    public Feature createFeature(FeatureProvider data, FeatureType type)
1807
        throws DataException {
1808
        // FIXME: falta por implementar
1809
        // Comprobar si es un subtipo del feature de data
1810
        // y construir un feature usando el subtipo.
1811
        // Probablemente requiera generar una copia del data.
1812
        throw new NotYetImplemented();
1813
    }
1814

    
1815
    public EditableFeature createNewFeature(FeatureType type,
1816
        Feature defaultValues) throws DataException {
1817
        try {
1818
            FeatureProvider data = createNewFeatureProvider(type);
1819
            DefaultEditableFeature feature =
1820
                new DefaultEditableFeature(this, data);
1821
            feature.initializeValues(defaultValues);
1822
            data.setNew(true);
1823

    
1824
            return feature;
1825
        } catch (Exception e) {
1826
            throw new CreateFeatureException(e, getName());
1827
        }
1828
    }
1829

    
1830
    private FeatureProvider createNewFeatureProvider(FeatureType type)
1831
        throws DataException {
1832
        type = this.fixFeatureType((DefaultFeatureType) type);
1833
        FeatureProvider data = this.provider.createFeatureProvider(type);
1834
        data.setNew(true);
1835
        if (type.hasOID() && (data.getOID() == null)) {
1836
            data.setOID(this.provider.createNewOID());
1837
        } else {
1838
            data.setOID(this.getTemporalOID());
1839
        }
1840
        return data;
1841

    
1842
    }
1843

    
1844
    public EditableFeature createNewFeature(FeatureType type,
1845
        boolean defaultValues) throws DataException {
1846
        try {
1847
            FeatureProvider data = createNewFeatureProvider(type);
1848
            DefaultEditableFeature feature =
1849
                new DefaultEditableFeature(this, data);
1850
            if (defaultValues) {
1851
                feature.initializeValues();
1852
            }
1853
            return feature;
1854
        } catch (Exception e) {
1855
            throw new CreateFeatureException(e, getName());
1856
        }
1857
    }
1858

    
1859
    public EditableFeature createNewFeature(boolean defaultValues)
1860
        throws DataException {
1861
        return this.createNewFeature(this.getDefaultFeatureType(),
1862
            defaultValues);
1863
    }
1864

    
1865
    public EditableFeature createNewFeature() throws DataException {
1866
        return this.createNewFeature(this.getDefaultFeatureType(), true);
1867
    }
1868

    
1869
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
1870
        FeatureType ft = this.getDefaultFeatureType();
1871
        EditableFeature f = this.createNewFeature(ft, false);
1872
        Iterator it = ft.iterator();
1873
        while(it.hasNext()) {
1874
            FeatureAttributeDescriptor desc = (FeatureAttributeDescriptor) it.next();
1875
            try {
1876
                f.set(desc.getName(), defaultValues.get(desc.getName()));
1877
            } catch(Throwable th) {
1878
                // Ignore
1879
            }
1880
        }
1881
        return f;
1882
    }
1883

    
1884
    public EditableFeatureType createFeatureType() {
1885
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType();
1886
        return ftype;
1887
    }
1888

    
1889
    public EditableFeatureType createFeatureType(String id) {
1890
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(id);
1891
        return ftype;
1892
    }
1893

    
1894
    //
1895
    // ====================================================================
1896
    // Index related methods
1897
    //
1898

    
1899
    public FeatureIndexes getIndexes() {
1900
        return this.indexes;
1901
    }
1902

    
1903
    public FeatureIndex createIndex(FeatureType featureType,
1904
        String attributeName, String indexName) throws DataException {
1905
        return createIndex(null, featureType, attributeName, indexName);
1906
    }
1907

    
1908
    public FeatureIndex createIndex(String indexTypeName,
1909
        FeatureType featureType, String attributeName, String indexName)
1910
        throws DataException {
1911

    
1912
        return createIndex(indexTypeName, featureType, attributeName,
1913
            indexName, false, null);
1914
    }
1915

    
1916
    public FeatureIndex createIndex(FeatureType featureType,
1917
        String attributeName, String indexName, Observer observer)
1918
        throws DataException {
1919
        return createIndex(null, featureType, attributeName, indexName,
1920
            observer);
1921
    }
1922

    
1923
    public FeatureIndex createIndex(String indexTypeName,
1924
        FeatureType featureType, String attributeName, String indexName,
1925
        final Observer observer) throws DataException {
1926

    
1927
        return createIndex(indexTypeName, featureType, attributeName,
1928
            indexName, true, observer);
1929
    }
1930

    
1931
    private FeatureIndex createIndex(String indexTypeName,
1932
        FeatureType featureType, String attributeName, String indexName,
1933
        boolean background, final Observer observer) throws DataException {
1934

    
1935
        checkNotInAppendMode();
1936
        FeatureIndexProviderServices index = null;
1937
        index =
1938
            dataManager.createFeatureIndexProvider(indexTypeName, this,
1939
                featureType, indexName,
1940
                featureType.getAttributeDescriptor(attributeName));
1941

    
1942
        try {
1943
            index.fill(background, observer);
1944
        } catch (FeatureIndexException e) {
1945
            throw new InitializeException(index.getName(), e);
1946
        }
1947

    
1948
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
1949
        return index;
1950
    }
1951

    
1952
    //
1953
    // ====================================================================
1954
    // Transforms related methods
1955
    //
1956

    
1957
    public FeatureStoreTransforms getTransforms() {
1958
        return this.transforms;
1959
    }
1960

    
1961
    public FeatureQuery createFeatureQuery() {
1962
        return new DefaultFeatureQuery();
1963
    }
1964

    
1965
    public DataQuery createQuery() {
1966
        return createFeatureQuery();
1967
    }
1968

    
1969
    //
1970
    // ====================================================================
1971
    // UndoRedo related methods
1972
    //
1973

    
1974
    public boolean canRedo() {
1975
        return commands.canRedo();
1976
    }
1977

    
1978
    public boolean canUndo() {
1979
        return commands.canUndo();
1980
    }
1981

    
1982
    public void redo(int num) throws RedoException {
1983
        for (int i = 0; i < num; i++) {
1984
            redo();
1985
        }
1986
    }
1987

    
1988
    public void undo(int num) throws UndoException {
1989
        for (int i = 0; i < num; i++) {
1990
            undo();
1991
        }
1992
    }
1993

    
1994
    //
1995
    // ====================================================================
1996
    // Metadata related methods
1997
    //
1998

    
1999
    public Object getMetadataID() {
2000
        return this.provider.getSourceId();
2001
    }
2002

    
2003
    public void delegate(DynObject dynObject) {
2004
        this.metadata.delegate(dynObject);
2005
    }
2006

    
2007
    public DynClass getDynClass() {
2008
        return this.metadata.getDynClass();
2009
    }
2010

    
2011
        public Object getDynValue(String name) throws DynFieldNotFoundException {
2012
                if( this.transforms.hasDynValue(name) ) {
2013
                        return this.transforms.getDynValue(name);
2014
                }
2015
                if (this.metadata.hasDynValue(name)) {
2016
                        return this.metadata.getDynValue(name);
2017
                }
2018
                if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2019
                        return this.provider.getProviderName();
2020
                } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2021
                        return this.provider.getSourceId();
2022
                } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2023
                        try {
2024
                                return this.getDefaultFeatureType();
2025
                        } catch (DataException e) {
2026
                                return null;
2027
                        }
2028
                }
2029
                return this.metadata.getDynValue(name);
2030
        }
2031

    
2032
    public boolean hasDynValue(String name) {
2033
                if( this.transforms.hasDynValue(name) ) {
2034
                        return true;
2035
                }
2036
        return this.metadata.hasDynValue(name);
2037
    }
2038

    
2039
    public void implement(DynClass dynClass) {
2040
        this.metadata.implement(dynClass);
2041
    }
2042

    
2043
    public Object invokeDynMethod(String name, Object[] args)
2044
        throws DynMethodException {
2045
        return this.metadata.invokeDynMethod(this, name, args);
2046
    }
2047

    
2048
    public Object invokeDynMethod(int code, Object[] args)
2049
        throws DynMethodException {
2050
        return this.metadata.invokeDynMethod(this, code, args);
2051
    }
2052

    
2053
    public void setDynValue(String name, Object value)
2054
        throws DynFieldNotFoundException {
2055
                if( this.transforms.hasDynValue(name) ) {
2056
                        this.transforms.setDynValue(name, value);
2057
                        return;
2058
                }
2059
        this.metadata.setDynValue(name, value);
2060

    
2061
    }
2062

    
2063
    /*
2064
     * (non-Javadoc)
2065
     *
2066
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2067
     */
2068
    public Set getMetadataChildren() {
2069
        return this.metadataChildren;
2070
    }
2071

    
2072
    /*
2073
     * (non-Javadoc)
2074
     *
2075
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2076
     */
2077
    public String getMetadataName() {
2078
        return this.provider.getProviderName();
2079
    }
2080

    
2081
    public FeatureTypeManager getFeatureTypeManager() {
2082
        return this.featureTypeManager;
2083
    }
2084

    
2085
    public long getFeatureCount() throws DataException {
2086
        if (featureCount == null) {
2087
            featureCount = new Long(this.provider.getFeatureCount());
2088
        }
2089
        if (this.isEditing()) {
2090
            if(this.isAppending()) {
2091
                try{
2092
                    throw new IllegalStateException();
2093
                } catch(IllegalStateException e) {
2094
                    LOG.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND");
2095
                    e.printStackTrace();
2096
                }
2097
                return -1;
2098
            } else {
2099
                return featureCount.longValue()
2100
                    + this.featureManager.getDeltaSize();
2101
            }
2102
        }
2103
        return featureCount.longValue();
2104
    }
2105

    
2106
    private Long getTemporalOID() {
2107
        return new Long(this.temporalOid++);
2108
    }
2109

    
2110
    public FeatureType getProviderFeatureType(String featureTypeId) {
2111
        if (featureTypeId == null) {
2112
            return this.defaultFeatureType;
2113
        }
2114
        FeatureType type;
2115
        Iterator iter = this.featureTypes.iterator();
2116
        while (iter.hasNext()) {
2117
            type = (FeatureType) iter.next();
2118
            if (type.getId().equals(featureTypeId)) {
2119
                return type;
2120
            }
2121
        }
2122
        return null;
2123
    }
2124

    
2125
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2126
        return ((DefaultFeature) feature).getData();
2127
    }
2128

    
2129
    public DataStore getStore() {
2130
        return this;
2131
    }
2132

    
2133
    public FeatureStore getFeatureStore() {
2134
        return this;
2135
    }
2136

    
2137
    public void createCache(String name, DynObject parameters)
2138
        throws DataException {
2139
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2140
        if (cache == null) {
2141
            throw new CreateException("FeaureCacheProvider", null);
2142
        }
2143
        cache.apply(this, provider);
2144
        provider = cache;
2145

    
2146
        featureCount = null;
2147
    }
2148

    
2149
    public FeatureCache getCache() {
2150
        return cache;
2151
    }
2152

    
2153
    public void clear() {
2154
        if (metadata != null) {
2155
            metadata.clear();
2156
        }
2157
    }
2158

    
2159
    public String getName() {
2160
        return this.provider.getName();
2161
    }
2162

    
2163
    public String getFullName() {
2164
        try {
2165
            return this.provider.getFullName();
2166
        } catch(Throwable th) {
2167
            return null;
2168
        }
2169
    }
2170

    
2171
    public String getProviderName() {
2172
        return this.provider.getProviderName();
2173
    }
2174

    
2175
    public boolean isKnownEnvelope() {
2176
        return this.provider.isKnownEnvelope();
2177
    }
2178

    
2179
    public boolean hasRetrievedFeaturesLimit() {
2180
        return this.provider.hasRetrievedFeaturesLimit();
2181
    }
2182

    
2183
    public int getRetrievedFeaturesLimit() {
2184
        return this.provider.getRetrievedFeaturesLimit();
2185
    }
2186

    
2187
    public Interval getInterval() {
2188
        return this.provider.getInterval();
2189
    }
2190

    
2191
    public Collection getTimes() {
2192
        return this.provider.getTimes();
2193
    }
2194

    
2195
    public Collection getTimes(Interval interval) {
2196
        return this.provider.getTimes(interval);
2197
    }
2198

    
2199
    /* (non-Javadoc)
2200
     * @see java.lang.Object#clone()
2201
     */
2202
    public Object clone() throws CloneNotSupportedException {
2203

    
2204
        DataStoreParameters dsp = getParameters();
2205

    
2206
        DefaultFeatureStore cloned_store = null;
2207

    
2208
        try {
2209
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2210
                openStore(this.getProviderName(), dsp);
2211
            if (transforms != null) {
2212
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2213
                cloned_store.transforms.setStoreForClone(cloned_store);
2214
            }
2215
        } catch (Exception e) {
2216
            throw new CloneException(e);
2217
        }
2218
        return cloned_store;
2219

    
2220
    }
2221

    
2222
    public Feature getFeature(DynObject dynobject) {
2223
        if (dynobject instanceof DynObjectFeatureFacade){
2224
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2225
            return f;
2226
        }
2227
        return null;
2228
    }
2229

    
2230
    public Iterator iterator() {
2231
        try {
2232
            return this.getFeatureSet().fastIterator();
2233
        } catch (DataException ex) {
2234
            throw new RuntimeException(ex);
2235
        }
2236
    }
2237
    
2238
}