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

History | View | Annotate | Download (74.7 KB)

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

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

    
27
import 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.slf4j.Logger;
40
import org.slf4j.LoggerFactory;
41

    
42
import org.gvsig.fmap.dal.DALLocator;
43
import org.gvsig.fmap.dal.DataManager;
44
import org.gvsig.fmap.dal.DataQuery;
45
import org.gvsig.fmap.dal.DataServerExplorer;
46
import org.gvsig.fmap.dal.DataSet;
47
import org.gvsig.fmap.dal.DataStore;
48
import org.gvsig.fmap.dal.DataStoreNotification;
49
import org.gvsig.fmap.dal.DataStoreParameters;
50
import org.gvsig.fmap.dal.exception.CloneException;
51
import org.gvsig.fmap.dal.exception.CloseException;
52
import org.gvsig.fmap.dal.exception.CreateException;
53
import org.gvsig.fmap.dal.exception.DataException;
54
import org.gvsig.fmap.dal.exception.InitializeException;
55
import org.gvsig.fmap.dal.exception.OpenException;
56
import org.gvsig.fmap.dal.exception.ReadException;
57
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
58
import org.gvsig.fmap.dal.exception.WriteException;
59
import org.gvsig.fmap.dal.feature.EditableFeature;
60
import org.gvsig.fmap.dal.feature.EditableFeatureType;
61
import org.gvsig.fmap.dal.feature.Feature;
62
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
63
import org.gvsig.fmap.dal.feature.FeatureCache;
64
import org.gvsig.fmap.dal.feature.FeatureIndex;
65
import org.gvsig.fmap.dal.feature.FeatureIndexes;
66
import org.gvsig.fmap.dal.feature.FeatureLocks;
67
import org.gvsig.fmap.dal.feature.FeatureQuery;
68
import org.gvsig.fmap.dal.feature.FeatureReference;
69
import org.gvsig.fmap.dal.feature.FeatureReferenceSelection;
70
import org.gvsig.fmap.dal.feature.FeatureSelection;
71
import org.gvsig.fmap.dal.feature.FeatureSet;
72
import org.gvsig.fmap.dal.feature.FeatureStore;
73
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
74
import org.gvsig.fmap.dal.feature.FeatureStoreTransforms;
75
import org.gvsig.fmap.dal.feature.FeatureType;
76
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
77
import org.gvsig.fmap.dal.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.featureset.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.spi.DefaultFeatureProvider;
109
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
110
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
111
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
112
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
113
import org.gvsig.fmap.dal.feature.spi.cache.FeatureCacheProvider;
114
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProviderServices;
115
import org.gvsig.fmap.dal.impl.DefaultDataManager;
116
import org.gvsig.fmap.dal.resource.Resource;
117
import org.gvsig.fmap.dal.spi.DataStoreInitializer;
118
import org.gvsig.fmap.dal.spi.DataStoreProvider;
119
import org.gvsig.fmap.geom.primitive.Envelope;
120
import org.gvsig.metadata.MetadataLocator;
121
import org.gvsig.metadata.MetadataManager;
122
import org.gvsig.metadata.exceptions.MetadataException;
123
import org.gvsig.timesupport.Interval;
124
import org.gvsig.tools.ToolsLocator;
125
import org.gvsig.tools.dispose.DisposableIterator;
126
import org.gvsig.tools.dispose.impl.AbstractDisposable;
127
import org.gvsig.tools.dynobject.DelegatedDynObject;
128
import org.gvsig.tools.dynobject.DynClass;
129
import org.gvsig.tools.dynobject.DynObject;
130
import org.gvsig.tools.dynobject.DynObjectManager;
131
import org.gvsig.tools.dynobject.DynStruct;
132
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
133
import org.gvsig.tools.dynobject.exception.DynMethodException;
134
import org.gvsig.tools.exception.BaseException;
135
import org.gvsig.tools.exception.NotYetImplemented;
136
import org.gvsig.tools.identitymanagement.SimpleIdentityManager;
137
import org.gvsig.tools.observer.Observable;
138
import org.gvsig.tools.observer.Observer;
139
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
140
import org.gvsig.tools.persistence.PersistenceManager;
141
import org.gvsig.tools.persistence.Persistent;
142
import org.gvsig.tools.persistence.PersistentState;
143
import org.gvsig.tools.persistence.exception.PersistenceException;
144
import org.gvsig.tools.undo.RedoException;
145
import org.gvsig.tools.undo.UndoException;
146
import org.gvsig.tools.undo.command.Command;
147
import org.gvsig.tools.visitor.Visitor;
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
                    throw new PersistenceCantFindDefaultFeatureTypeException(
519
                        this.getName(), defFTypeid);
520
                }
521
                this.defaultFeatureType = ftype;
522
            }
523

    
524
        } catch (InitializeException e) {
525
            throw new PersistenceException(e);
526
        } catch (DataException e) {
527
            throw new PersistenceException(e);
528
        }
529

    
530
    }
531

    
532
    public static void registerPersistenceDefinition() {
533
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
534
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
535
            DynStruct definition =
536
                manager.addDefinition(DefaultFeatureStore.class,
537
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
538
                        + " Persistent definition", null, null);
539
            definition.addDynFieldString("dataStoreName").setMandatory(true)
540
                .setPersistent(true);
541

    
542
            definition.addDynFieldObject("parameters")
543
                .setClassOfValue(DynObject.class).setMandatory(true)
544
                .setPersistent(true);
545

    
546
            definition.addDynFieldObject("selection")
547
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
548
                .setPersistent(true);
549

    
550
            definition.addDynFieldObject("transforms")
551
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
552
                .setMandatory(true).setPersistent(true);
553

    
554
            definition.addDynFieldMap("evaluatedAttributes")
555
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
556
                .setMandatory(false).setPersistent(true);
557

    
558
            definition.addDynFieldString("defaultFeatureTypeId")
559
                .setMandatory(true).setPersistent(true);
560
        }
561
    }
562

    
563
    public static void registerMetadataDefinition() throws MetadataException {
564
        MetadataManager manager = MetadataLocator.getMetadataManager();
565
        if (manager.getDefinition(METADATA_DEFINITION_NAME) == null) {
566
            DynStruct metadataDefinition =
567
                manager.addDefinition(METADATA_DEFINITION_NAME, null);
568
            metadataDefinition.extend(manager
569
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
570
        }
571
    }
572

    
573
    //
574
    // ====================================================================
575
    // Gestion de la seleccion
576
    //
577

    
578
    public void setSelection(DataSet selection) throws DataException {
579
        this.setSelection((FeatureSet) selection);
580
    }
581

    
582
    public DataSet createSelection() throws DataException {
583
        return createFeatureSelection();
584
    }
585

    
586
    public DataSet getSelection() throws DataException {
587
        return this.getFeatureSelection();
588
    }
589

    
590
    public void setSelection(FeatureSet selection) throws DataException {
591
        setSelection(selection, true);
592
    }
593

    
594
    /**
595
     * @see #setSelection(FeatureSet)
596
     * @param undoable
597
     *            if the action must be undoable
598
     */
599
    public void setSelection(FeatureSet selection, boolean undoable)
600
        throws DataException {
601
        if (selection == null) {
602
            if (undoable) {
603
                throw new SelectionNotAllowedException(getName());
604
            }
605

    
606
        } else {
607
            if (selection.equals(this.selection)) {
608
                return;
609
            }
610
            if (!selection.isFromStore(this)) {
611
                throw new SelectionNotAllowedException(getName());
612
            }
613
        }
614

    
615
        if (this.selection != null) {
616
            this.selection.deleteObserver(this);
617
        }
618
        if (selection == null) {
619
            if (this.selection != null) {
620
                this.selection.dispose();
621
            }
622
            this.selection = null;
623
            return;
624
        }
625
        if (selection instanceof FeatureSelection) {
626
            if (undoable && isEditing()) {
627
                commands.selectionSet(this, this.selection,
628
                    (FeatureSelection) selection);
629
            }
630
            if (this.selection != null) {
631
                this.selection.dispose();
632
            }
633
            this.selection = (FeatureSelection) selection;
634
        } else {
635
            if (undoable && isEditing()) {
636
                commands.startComplex("_selectionSet");
637
            }
638
            if (selection instanceof DefaultFeatureSelection) {
639
                DefaultFeatureSelection defSelection =
640
                    (DefaultFeatureSelection) selection;
641
                defSelection.deselectAll(undoable);
642
                defSelection.select(selection, undoable);
643
            } else {
644
                this.selection.deselectAll();
645
                this.selection.select(selection);
646
            }
647
            if (undoable && isEditing()) {
648
                commands.endComplex();
649
            }
650
        }
651
        this.selection.addObserver(this);
652

    
653
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
654
    }
655

    
656
    public FeatureSelection createFeatureSelection() throws DataException {
657
        return this.provider.createFeatureSelection();
658
    }
659

    
660
    public FeatureSelection getFeatureSelection() throws DataException {
661
        if (selection == null) {
662
            this.selection = createFeatureSelection();
663
            this.selection.addObserver(this);
664
        }
665
        return selection;
666
    }
667

    
668
    //
669
    // ====================================================================
670
    // Gestion de notificaciones
671
    //
672

    
673
    public void notifyChange(String notification) {
674
        if (delegateObservable != null) {
675
            notifyChange(new DefaultFeatureStoreNotification(this, notification));
676
        }
677

    
678
    }
679

    
680
    public void notifyChange(String notification, FeatureProvider data) {
681
        try {
682
            notifyChange(notification, createFeature(data));
683
        } catch (DataException ex) {
684
            LOG.error("Error notifying about the notification: " + notification
685
                + ", with the data: " + data, ex);
686
        }
687
    }
688

    
689
    public void notifyChange(String notification, Feature feature) {
690
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
691
            feature));
692
    }
693

    
694
    public void notifyChange(String notification, Command command) {
695
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
696
            command));
697
    }
698

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

    
704
    public void notifyChange(FeatureStoreNotification storeNotification) {
705
        delegateObservable.notifyObservers(storeNotification);
706
    }
707

    
708
    public void notifyChange(String notification, Resource resource) {
709
        notifyChange(new DefaultFeatureStoreNotification(this,
710
            DataStoreNotification.RESOURCE_CHANGED));
711
    }
712

    
713
    //
714
    // ====================================================================
715
    // Gestion de bloqueos
716
    //
717

    
718
    public boolean isLocksSupported() {
719
        return this.provider.isLocksSupported();
720
    }
721

    
722
    public FeatureLocks getLocks() throws DataException {
723
        if (!this.provider.isLocksSupported()) {
724
            LOG.warn("Locks not supported");
725
            return null;
726
        }
727
        if (locks == null) {
728
            this.locks = this.provider.createFeatureLocks();
729
        }
730
        return locks;
731
    }
732

    
733
    //
734
    // ====================================================================
735
    // Interface Observable
736
    //
737

    
738
    public void disableNotifications() {
739
        this.delegateObservable.disableNotifications();
740

    
741
    }
742

    
743
    public void enableNotifications() {
744
        this.delegateObservable.enableNotifications();
745
    }
746

    
747
    public void beginComplexNotification() {
748
        this.delegateObservable.beginComplexNotification();
749

    
750
    }
751

    
752
    public void endComplexNotification() {
753
        this.delegateObservable.endComplexNotification();
754

    
755
    }
756

    
757
    public void addObserver(Observer observer) {
758
        if (delegateObservable != null) {
759
            this.delegateObservable.addObserver(observer);
760
        }
761
    }
762

    
763
    public void deleteObserver(Observer observer) {
764
        if (delegateObservable != null) {
765
            this.delegateObservable.deleteObserver(observer);
766
        }
767
    }
768

    
769
    public void deleteObservers() {
770
        this.delegateObservable.deleteObservers();
771

    
772
    }
773

    
774
    //
775
    // ====================================================================
776
    // Interface Observer
777
    //
778
    // Usado para observar:
779
    // - su seleccion
780
    // - sus bloqueos
781
    // - sus recursos
782
    //
783

    
784
    public void update(Observable observable, Object notification) {
785
        if (observable instanceof FeatureSet) {
786
            if (observable == this.selection) {
787
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
788
            } else
789
                if (observable == this.locks) {
790
                    this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
791
                }
792

    
793
        } else
794
            if (observable instanceof FeatureStoreProvider) {
795
                if (observable == this.provider) {
796

    
797
                }
798

    
799
            }
800
    }
801

    
802
    //
803
    // ====================================================================
804
    // Edicion
805
    //
806

    
807
    private void newVersionOfUpdate() {
808
        this.versionOfUpdate++;
809
    }
810

    
811
    private long currentVersionOfUpdate() {
812
        return this.versionOfUpdate;
813
    }
814

    
815
    private void checkInEditingMode() throws NeedEditingModeException {
816
        if (mode != MODE_FULLEDIT) {
817
            throw new NeedEditingModeException(this.getName());
818
        }
819
    }
820

    
821
    private void checkNotInAppendMode() throws IllegalStateException {
822
        if (mode == MODE_APPEND) {
823
                        throw new IllegalStateException("Error: store "
824
                                        + this.getFullName() + " is in append mode");
825
        }
826
    }
827

    
828
    private void checkIsOwnFeature(Feature feature)
829
        throws IllegalFeatureException {
830
        if (((DefaultFeature) feature).getStore() != this) {
831
            throw new IllegalFeatureException(this.getName());
832
        }
833
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
834
        // fixFeatureType((DefaultFeatureType) feature.getType());
835
    }
836

    
837
    private void exitEditingMode() {
838
        if (commands != null) {
839
            commands.clear();
840
            commands = null;
841
        }
842

    
843
        if (featureTypeManager != null) {
844
            featureTypeManager.dispose();
845
            featureTypeManager = null;
846

    
847
        }
848

    
849
        // TODO implementar un dispose para estos dos
850
        featureManager = null;
851
        spatialManager = null;
852

    
853
        featureCount = null;
854

    
855
        mode = MODE_QUERY;
856
        hasStrongChanges = true; // Lo deja a true por si las moscas
857
        hasInserts = true;
858
    }
859

    
860
    synchronized public void edit() throws DataException {
861
        edit(MODE_FULLEDIT);
862
    }
863

    
864
    synchronized public void edit(int mode) throws DataException {
865
        LOG.debug("Starting editing in mode: {}", new Integer(mode));
866
        try {
867
            if (this.mode != MODE_QUERY) {
868
                throw new AlreadyEditingException(this.getName());
869
            }
870
            if (!this.provider.supportsAppendMode()) {
871
                mode = MODE_FULLEDIT;
872
            }
873
            switch (mode) {
874
            case MODE_QUERY:
875
                throw new IllegalStateException(this.getName());
876

    
877
            case MODE_FULLEDIT:
878
                if (!this.transforms.isEmpty()) {
879
                    throw new IllegalStateException(this.getName());
880
                }
881
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
882
                invalidateIndexes();
883
                featureManager =
884
                    new FeatureManager(new MemoryExpansionAdapter());
885
                featureTypeManager =
886
                    new FeatureTypeManager(this, new MemoryExpansionAdapter());
887
                spatialManager =
888
                    new SpatialManager(this, provider.getEnvelope());
889

    
890
                commands =
891
                    new DefaultFeatureCommandsStack(this, featureManager,
892
                        spatialManager, featureTypeManager);
893
                this.mode = MODE_FULLEDIT;
894
                hasStrongChanges = false;
895
                hasInserts = false;
896
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
897
                break;
898
            case MODE_APPEND:
899
                if (!this.transforms.isEmpty()) {
900
                    throw new IllegalStateException(this.getName());
901
                }
902
                notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING);
903
                invalidateIndexes();
904
                this.provider.beginAppend();
905
                this.mode = MODE_APPEND;
906
                hasInserts = false;
907
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
908
                break;
909
            }
910
        } catch (Exception e) {
911
            throw new StoreEditException(e, this.getName());
912
        }
913
    }
914

    
915
    private void invalidateIndexes() {
916
        setIndexesValidStatus(false);
917
    }
918

    
919
    private void setIndexesValidStatus(boolean valid) {
920
        FeatureIndexes indexes = getIndexes();
921
        LOG.debug("Setting the store indexes to valid status {}: {}", (valid
922
            ? Boolean.TRUE : Boolean.FALSE), indexes);
923
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
924
            FeatureIndex index = (FeatureIndex) iterator.next();
925
            if (index instanceof FeatureIndexProviderServices) {
926
                FeatureIndexProviderServices indexServices =
927
                    (FeatureIndexProviderServices) index;
928
                indexServices.setValid(valid);
929
            }
930
        }
931
    }
932

    
933
    private void updateIndexes() throws FeatureIndexException {
934
        FeatureIndexes indexes = getIndexes();
935
        LOG.debug("Refilling indexes: {}", indexes);
936
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
937
            FeatureIndex index = (FeatureIndex) iterator.next();
938
            if (index instanceof FeatureIndexProviderServices) {
939
                FeatureIndexProviderServices indexServices =
940
                    (FeatureIndexProviderServices) index;
941
                indexServices.fill(true, null);
942
            }
943
        }
944
    }
945

    
946
    private void waitForIndexes() {
947
        FeatureIndexes indexes = getIndexes();
948
        LOG.debug("Waiting for indexes to finish filling: {}", indexes);
949
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
950
            FeatureIndex index = (FeatureIndex) iterator.next();
951
            if (index instanceof FeatureIndexProviderServices) {
952
                FeatureIndexProviderServices indexServices =
953
                    (FeatureIndexProviderServices) index;
954
                indexServices.waitForIndex();
955
            }
956
        }
957
    }
958

    
959
    private void disposeIndexes() {
960
        FeatureIndexes indexes = getIndexes();
961
        LOG.debug("Disposing indexes: {}", indexes);
962
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
963
            FeatureIndex index = (FeatureIndex) iterator.next();
964
            if (index instanceof FeatureIndexProviderServices) {
965
                FeatureIndexProviderServices indexServices =
966
                    (FeatureIndexProviderServices) index;
967
                indexServices.dispose();
968
            }
969
        }
970
    }
971

    
972
    public boolean isEditing() {
973
        return mode == MODE_FULLEDIT;
974
    }
975

    
976
    public boolean isAppending() {
977
        return mode == MODE_APPEND;
978
    }
979

    
980
    synchronized public void update(EditableFeatureType type)
981
        throws DataException {
982
        try {
983
            checkInEditingMode();
984
            if (type == null) {
985
                throw new NullFeatureTypeException(getName());
986
            }
987
            // FIXME: Comprobar que es un featureType aceptable.
988
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type);
989
            newVersionOfUpdate();
990

    
991
            FeatureType oldt = type.getSource().getCopy();
992
            FeatureType newt = type.getCopy();
993
            commands.update(newt, oldt);
994

    
995
            if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
996
                hasStrongChanges = true;
997
            }
998
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
999
        } catch (Exception e) {
1000
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1001
        }
1002
    }
1003

    
1004
    public void delete(Feature feature) throws DataException {
1005
        this.commands.delete(feature);
1006
    }
1007

    
1008
    synchronized public void doDelete(Feature feature) throws DataException {
1009
        try {
1010
            checkInEditingMode();
1011
            checkIsOwnFeature(feature);
1012
            if (feature instanceof EditableFeature) {
1013
                throw new StoreDeleteEditableFeatureException(getName());
1014
            }
1015
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1016

    
1017
            //Update the featureManager and the spatialManager
1018
            featureManager.delete(feature.getReference());
1019
            spatialManager.deleteFeature(feature);
1020

    
1021
            newVersionOfUpdate();
1022
            hasStrongChanges = true;
1023
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1024
        } catch (Exception e) {
1025
            throw new StoreDeleteFeatureException(e, this.getName());
1026
        }
1027
    }
1028

    
1029
    private static EditableFeature lastChangedFeature = null;
1030

    
1031
    public synchronized void insert(EditableFeature feature)
1032
        throws DataException {
1033
        LOG.debug("In editing mode {}, insert feature: {}", new Integer(mode),
1034
            feature);
1035
        try {
1036
            switch (mode) {
1037
            case MODE_QUERY:
1038
                throw new NeedEditingModeException(this.getName());
1039

    
1040
            case MODE_APPEND:
1041
                checkIsOwnFeature(feature);
1042
                if (feature.getSource() != null) {
1043
                    throw new NoNewFeatureInsertException(this.getName());
1044
                }
1045
                this.featureCount = null;
1046
                notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1047
                feature.validate(Feature.UPDATE);
1048
                provider.append(((DefaultEditableFeature) feature).getData());
1049
                hasStrongChanges = true;
1050
                hasInserts = true;
1051
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1052
                break;
1053

    
1054
            case MODE_FULLEDIT:
1055
                if (feature.getSource() != null) {
1056
                    throw new NoNewFeatureInsertException(this.getName());
1057
                }
1058
                commands.insert(feature);
1059
            }
1060
        } catch (Exception e) {
1061
            throw new StoreInsertFeatureException(e, this.getName());
1062
        }
1063
    }
1064

    
1065
    synchronized public void doInsert(EditableFeature feature)
1066
        throws DataException {
1067
        checkIsOwnFeature(feature);
1068

    
1069
        waitForIndexes();
1070

    
1071
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature);
1072
        newVersionOfUpdate();
1073
        if ((lastChangedFeature == null)
1074
            || (lastChangedFeature.getSource() != feature.getSource())) {
1075
            lastChangedFeature = feature;
1076
            feature.validate(Feature.UPDATE);
1077
            lastChangedFeature = null;
1078
        }
1079
        //Update the featureManager and the spatialManager
1080
        ((DefaultEditableFeature) feature).setInserted(true);
1081
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1082

    
1083

    
1084
        featureManager.add(newFeature);
1085
        spatialManager.insertFeature(newFeature);
1086

    
1087
        hasStrongChanges = true;
1088
        hasInserts = true;
1089
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1090
    }
1091

    
1092
    public void update(EditableFeature feature)
1093
    throws DataException {
1094
        if ((feature).getSource() == null) {
1095
            insert(feature);
1096
            return;
1097
        }
1098
        commands.update(feature, feature.getSource());
1099
    }
1100

    
1101
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1102
        throws DataException {
1103
        try {
1104
            checkInEditingMode();
1105
            checkIsOwnFeature(feature);
1106
            notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature);
1107
            newVersionOfUpdate();
1108
            if ((lastChangedFeature == null)
1109
                || (lastChangedFeature.getSource() != feature.getSource())) {
1110
                lastChangedFeature = feature;
1111
                feature.validate(Feature.UPDATE);
1112
                lastChangedFeature = null;
1113
            }
1114

    
1115
            //Update the featureManager and the spatialManager
1116
            Feature newf = feature.getNotEditableCopy();
1117
            featureManager.update(newf, oldFeature);
1118
            spatialManager.updateFeature(newf, oldFeature);
1119

    
1120
            hasStrongChanges = true;
1121
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1122
        } catch (Exception e) {
1123
            throw new StoreUpdateFeatureException(e, this.getName());
1124
        }
1125
    }
1126

    
1127
    synchronized public void redo() throws RedoException {
1128
        Command redo = commands.getNextRedoCommand();
1129
        try {
1130
            checkInEditingMode();
1131
        } catch (NeedEditingModeException ex) {
1132
            throw new RedoException(redo, ex);
1133
        }
1134
        notifyChange(FeatureStoreNotification.BEFORE_REDO, redo);
1135
        newVersionOfUpdate();
1136
        commands.redo();
1137
        hasStrongChanges = true;
1138
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1139
    }
1140

    
1141
    synchronized public void undo() throws UndoException {
1142
        Command undo = commands.getNextUndoCommand();
1143
        try {
1144
            checkInEditingMode();
1145
        } catch (NeedEditingModeException ex) {
1146
            throw new UndoException(undo, ex);
1147
        }
1148
        notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo);
1149
        newVersionOfUpdate();
1150
        commands.undo();
1151
        hasStrongChanges = true;
1152
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1153
    }
1154

    
1155
    public List getRedoInfos() {
1156
        if (isEditing() && (commands != null)) {
1157
            return commands.getRedoInfos();
1158
        } else {
1159
            return null;
1160
        }
1161
    }
1162

    
1163
    public List getUndoInfos() {
1164
        if (isEditing() && (commands != null)) {
1165
            return commands.getUndoInfos();
1166
        } else {
1167
            return null;
1168
        }
1169
    }
1170

    
1171
    public synchronized FeatureCommandsStack getCommandsStack()
1172
        throws DataException {
1173
        checkInEditingMode();
1174
        return commands;
1175
    }
1176

    
1177
    synchronized public void cancelEditing() throws DataException {
1178
        spatialManager.cancelModifies();
1179
        try {
1180
            checkInEditingMode();
1181

    
1182
            boolean clearSelection = this.hasStrongChanges;
1183
            if (this.selection instanceof FeatureReferenceSelection) {
1184
                clearSelection = this.hasInserts;
1185
            }
1186
            notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING);
1187
            exitEditingMode();
1188
            if (clearSelection) {
1189
                ((FeatureSelection) this.getSelection()).deselectAll();
1190
            }
1191
            updateIndexes();
1192
            notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);
1193
        } catch (Exception e) {
1194
            throw new StoreCancelEditingException(e, this.getName());
1195
        }
1196
    }
1197

    
1198
    synchronized public void finishEditing() throws DataException {
1199
        LOG.debug("finish editing of mode: {}", new Integer(mode));
1200
        try {
1201

    
1202
            /*
1203
             * Selection needs to be cleared when editing stops
1204
             * to prevent conflicts with selection remaining from
1205
             * editing mode.
1206
             */
1207
            ((FeatureSelection) this.getSelection()).deselectAll();
1208

    
1209
            switch (mode) {
1210
            case MODE_QUERY:
1211
                throw new NeedEditingModeException(this.getName());
1212

    
1213
            case MODE_APPEND:
1214
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1215
                provider.endAppend();
1216
                exitEditingMode();
1217
                updateIndexes();
1218
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1219
                break;
1220

    
1221
            case MODE_FULLEDIT:
1222
                if (hasStrongChanges && !this.allowWrite()) {
1223
                    throw new WriteNotAllowedException(getName());
1224
                }
1225
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1226
                if (hasStrongChanges) {
1227
                    validateFeatures(Feature.FINISH_EDITING);
1228

    
1229
                    /*
1230
                     * This will throw a PerformEditingExceptionif the provider
1231
                     * does not accept the changes (for example, an invalid field name)
1232
                     */
1233
                    provider.performChanges(featureManager.getDeleted(),
1234
                        featureManager.getInserted(),
1235
                        featureManager.getUpdated(),
1236
                        featureTypeManager.getFeatureTypesChanged());
1237
                }
1238
                exitEditingMode();
1239
                updateIndexes();
1240
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1241
                break;
1242
            }
1243
        } catch (PerformEditingException pee) {
1244
            throw new WriteException(provider.getSourceId().toString(), pee);
1245
        } catch (Exception e) {
1246
            throw new FinishEditingException(e);
1247
        }
1248
    }
1249

    
1250
    /**
1251
     * Save changes in the provider without leaving the edit mode.
1252
     * Do not call observers to communicate a change of ediding mode.
1253
     * The operation's history is eliminated to prevent inconsistencies
1254
     * in the data.
1255
     *
1256
     * @throws DataException
1257
     */
1258
    synchronized public void commitChanges() throws DataException {
1259
      LOG.debug("commitChanges of mode: {}", new Integer(mode));
1260
      if( !canCommitChanges() ) {
1261
              throw new WriteNotAllowedException(getName());
1262
      }
1263
      try {
1264
        switch (mode) {
1265
        case MODE_QUERY:
1266
          throw new NeedEditingModeException(this.getName());
1267

    
1268
        case MODE_APPEND:
1269
          this.provider.endAppend();
1270
          exitEditingMode();
1271
          invalidateIndexes();
1272
          this.provider.beginAppend();
1273
          hasInserts = false;
1274
          break;
1275

    
1276
        case MODE_FULLEDIT:
1277
          if (hasStrongChanges && !this.allowWrite()) {
1278
            throw new WriteNotAllowedException(getName());
1279
          }
1280
          if (hasStrongChanges) {
1281
            validateFeatures(Feature.FINISH_EDITING);
1282
            provider.performChanges(featureManager.getDeleted(),
1283
              featureManager.getInserted(),
1284
              featureManager.getUpdated(),
1285
              featureTypeManager.getFeatureTypesChanged());
1286
          }
1287
          invalidateIndexes();
1288
          featureManager =
1289
            new FeatureManager(new MemoryExpansionAdapter());
1290
          featureTypeManager =
1291
            new FeatureTypeManager(this, new MemoryExpansionAdapter());
1292
          spatialManager =
1293
            new SpatialManager(this, provider.getEnvelope());
1294

    
1295
          commands =
1296
            new DefaultFeatureCommandsStack(this, featureManager,
1297
              spatialManager, featureTypeManager);
1298
          featureCount = null;
1299
          hasStrongChanges = false;
1300
          hasInserts = false;
1301
          break;
1302
        }
1303
      } catch (Exception e) {
1304
        throw new FinishEditingException(e);
1305
      }
1306
    }
1307

    
1308
    synchronized public boolean canCommitChanges() throws DataException {
1309
        if ( !this.allowWrite()) {
1310
                return false;
1311
        }
1312
            switch (mode) {
1313
            default:
1314
        case MODE_QUERY:
1315
                return false;
1316

    
1317
        case MODE_APPEND:
1318
                return true;
1319

    
1320
        case MODE_FULLEDIT:
1321
            List types = this.getFeatureTypes();
1322
            for( int i=0; i<types.size(); i++ ) {
1323
                    Object type = types.get(i);
1324
                    if( type instanceof DefaultEditableFeatureType ) {
1325
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1326
                                    return false;
1327
                            }
1328
                    }
1329
            }
1330
            return true;
1331
            }
1332
    }
1333

    
1334
    public void beginEditingGroup(String description)
1335
        throws NeedEditingModeException {
1336
        checkInEditingMode();
1337
        commands.startComplex(description);
1338
    }
1339

    
1340
    public void endEditingGroup() throws NeedEditingModeException {
1341
        checkInEditingMode();
1342
        commands.endComplex();
1343
    }
1344

    
1345
    public boolean isAppendModeSupported() {
1346
        return this.provider.supportsAppendMode();
1347
    }
1348

    
1349
    public void export(DataServerExplorer explorer, String provider,
1350
        NewFeatureStoreParameters params) throws DataException {
1351

    
1352
        if (this.getFeatureTypes().size() != 1) {
1353
            throw new NotYetImplemented(
1354
                "export whith more than one type not yet implemented");
1355
        }
1356
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1357
        FeatureStore target = null;
1358
        FeatureSet features = null;
1359
        DisposableIterator iterator = null;
1360
        try {
1361
            FeatureType type = this.getDefaultFeatureType();
1362
            if ((params.getDefaultFeatureType() == null)
1363
                || (params.getDefaultFeatureType().size() == 0)) {
1364
                params.setDefaultFeatureType(type.getEditable());
1365

    
1366
            }
1367
            explorer.add(provider, params, true);
1368

    
1369
            DataManager manager = DALLocator.getDataManager();
1370
            target = (FeatureStore) manager.openStore(provider, params);
1371
            FeatureType targetType = target.getDefaultFeatureType();
1372

    
1373
            target.edit(MODE_APPEND);
1374
            FeatureAttributeDescriptor[] pk = type.getPrimaryKey();
1375
            if (featureSelection.getSize() > 0) {
1376
                features = this.getFeatureSelection();
1377
            } else {
1378
                if ((pk != null) && (pk.length > 0)) {
1379
                    FeatureQuery query = createFeatureQuery();
1380
                    for (int i = 0; i < pk.length; i++) {
1381
                        query.getOrder().add(pk[i].getName(), true);
1382
                    }
1383
                    features = this.getFeatureSet(query);
1384
                } else {
1385
                    features = this.getFeatureSet();
1386
                }
1387
            }
1388
            iterator = features.fastIterator();
1389
            while (iterator.hasNext()) {
1390
                DefaultFeature feature = (DefaultFeature) iterator.next();
1391
                target.insert(target.createNewFeature(targetType, feature));
1392
            }
1393
            target.finishEditing();
1394
            target.dispose();
1395
        } catch (Exception e) {
1396
            throw new DataExportException(e, params.toString());
1397
        } finally {
1398
            dispose(iterator);
1399
            dispose(features);
1400
            dispose(target);
1401
        }
1402
    }
1403

    
1404
    //
1405
    // ====================================================================
1406
    // Obtencion de datos
1407
    // getDataCollection, getFeatureCollection
1408
    //
1409

    
1410
    public DataSet getDataSet() throws DataException {
1411
        checkNotInAppendMode();
1412
        FeatureQuery query =
1413
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1414
        return new DefaultFeatureSet(this, query);
1415
    }
1416

    
1417
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1418
        checkNotInAppendMode();
1419
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1420
    }
1421

    
1422
    public void getDataSet(Observer observer) throws DataException {
1423
        checkNotInAppendMode();
1424
        this.getFeatureSet(null, observer);
1425
    }
1426

    
1427
    public void getDataSet(DataQuery dataQuery, Observer observer)
1428
        throws DataException {
1429
        checkNotInAppendMode();
1430
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1431
    }
1432

    
1433
    public FeatureSet getFeatureSet() throws DataException {
1434
        checkNotInAppendMode();
1435
        FeatureQuery query =
1436
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1437
        return new DefaultFeatureSet(this, query);
1438
    }
1439

    
1440
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1441
        throws DataException {
1442
        checkNotInAppendMode();
1443
        return new DefaultFeatureSet(this, featureQuery);
1444
    }
1445

    
1446
    public void accept(Visitor visitor) throws BaseException {
1447
        FeatureSet set = getFeatureSet();
1448
        try {
1449
            set.accept(visitor);
1450
        } finally {
1451
            set.dispose();
1452
        }
1453
    }
1454

    
1455
    public void accept(Visitor visitor, DataQuery dataQuery)
1456
        throws BaseException {
1457
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
1458
        try {
1459
            set.accept(visitor);
1460
        } finally {
1461
            set.dispose();
1462
        }
1463
    }
1464

    
1465
    public FeatureType getFeatureType(FeatureQuery featureQuery)
1466
        throws DataException {
1467
        DefaultFeatureType fType =
1468
            (DefaultFeatureType) this.getFeatureType(featureQuery
1469
                .getFeatureTypeId());
1470
        if( featureQuery.hasAttributeNames() || featureQuery.hasConstantsAttributeNames() ) {
1471
            return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames() );
1472
        }
1473
        return fType;
1474
    }
1475

    
1476
    public void getFeatureSet(Observer observer) throws DataException {
1477
        checkNotInAppendMode();
1478
        this.getFeatureSet(null, observer);
1479
    }
1480

    
1481
    public void getFeatureSet(FeatureQuery query, Observer observer)
1482
        throws DataException {
1483
        class LoadInBackGround implements Runnable {
1484

    
1485
            private FeatureStore store;
1486
            private FeatureQuery query;
1487
            private Observer observer;
1488

    
1489
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
1490
                Observer observer) {
1491
                this.store = store;
1492
                this.query = query;
1493
                this.observer = observer;
1494
            }
1495

    
1496
            void notify(FeatureStoreNotification theNotification) {
1497
                observer.update(store, theNotification);
1498
                return;
1499
            }
1500

    
1501
            public void run() {
1502
                FeatureSet set = null;
1503
                try {
1504
                    set = store.getFeatureSet(query);
1505
                    notify(new DefaultFeatureStoreNotification(store,
1506
                        FeatureStoreNotification.LOAD_FINISHED, set));
1507
                } catch (Exception e) {
1508
                    notify(new DefaultFeatureStoreNotification(store,
1509
                        FeatureStoreNotification.LOAD_FINISHED, e));
1510
                } finally {
1511
                    dispose(set);
1512
                }
1513
            }
1514
        }
1515

    
1516
        checkNotInAppendMode();
1517
        if (query == null) {
1518
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
1519
        }
1520
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
1521
        Thread thread = new Thread(task, "Load Feature Set in background");
1522
        thread.start();
1523
    }
1524

    
1525
    public Feature getFeatureByReference(FeatureReference reference)
1526
        throws DataException {
1527
        checkNotInAppendMode();
1528
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
1529
        FeatureType featureType;
1530
        if (ref.getFeatureTypeId() == null) {
1531
            featureType = this.getDefaultFeatureType();
1532
        } else {
1533
            featureType = this.getFeatureType(ref.getFeatureTypeId());
1534
        }
1535
        return this.getFeatureByReference(reference, featureType);
1536
    }
1537

    
1538
    public Feature getFeatureByReference(FeatureReference reference,
1539
        FeatureType featureType) throws DataException {
1540
        checkNotInAppendMode();
1541
        featureType = fixFeatureType((DefaultFeatureType) featureType);
1542
        if (this.mode == MODE_FULLEDIT) {
1543
            Feature f = featureManager.get(reference, this, featureType);
1544
            if (f != null) {
1545
                return f;
1546
            }
1547
        }
1548

    
1549
        FeatureType sourceFeatureType = featureType;
1550
        if (!this.transforms.isEmpty()) {
1551
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
1552
        }
1553
        // TODO comprobar que el id es de este store
1554

    
1555
        DefaultFeature feature =
1556
            new DefaultFeature(this,
1557
                this.provider.getFeatureProviderByReference(
1558
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
1559

    
1560
        if (!this.transforms.isEmpty()) {
1561
            return this.transforms.applyTransform(feature, featureType);
1562
        }
1563
        return feature;
1564
    }
1565

    
1566
    //
1567
    // ====================================================================
1568
    // Gestion de features
1569
    //
1570

    
1571
    private FeatureType fixFeatureType(DefaultFeatureType type)
1572
        throws DataException {
1573
        FeatureType original = this.getDefaultFeatureType();
1574

    
1575
        if ((type == null) || type.equals(original)) {
1576
            return original;
1577
        } else {
1578
            if (!type.isSubtypeOf(original)) {
1579
                Iterator iter = this.getFeatureTypes().iterator();
1580
                FeatureType tmpType;
1581
                boolean found = false;
1582
                while (iter.hasNext()) {
1583
                    tmpType = (FeatureType) iter.next();
1584
                    if (type.equals(tmpType)) {
1585
                        return type;
1586

    
1587
                    } else
1588
                        if (type.isSubtypeOf(tmpType)) {
1589
                            found = true;
1590
                            original = tmpType;
1591
                            break;
1592
                        }
1593

    
1594
                }
1595
                if (!found) {
1596
                    throw new IllegalFeatureTypeException(getName());
1597
                }
1598
            }
1599
        }
1600

    
1601
        // Checks that type has all fields of pk
1602
        // else add the missing attributes at the end.
1603
        if (!original.hasOID()) {
1604
            // Gets original pk attributes
1605
            DefaultEditableFeatureType edOriginal =
1606
                (DefaultEditableFeatureType) original.getEditable();
1607
            FeatureAttributeDescriptor orgAttr;
1608
            Iterator edOriginalIter = edOriginal.iterator();
1609
            while (edOriginalIter.hasNext()) {
1610
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1611
                if (!orgAttr.isPrimaryKey()) {
1612
                    edOriginalIter.remove();
1613
                }
1614
            }
1615

    
1616
            // Checks if all pk attributes are in type
1617
            Iterator typeIterator;
1618
            edOriginalIter = edOriginal.iterator();
1619
            FeatureAttributeDescriptor attr;
1620
            while (edOriginalIter.hasNext()) {
1621
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
1622
                typeIterator = type.iterator();
1623
                while (typeIterator.hasNext()) {
1624
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
1625
                    if (attr.getName().equals(orgAttr.getName())) {
1626
                        edOriginalIter.remove();
1627
                        break;
1628
                    }
1629
                }
1630
            }
1631

    
1632
            // add missing pk attributes if any
1633
            if (edOriginal.size() > 0) {
1634
                boolean isEditable = type instanceof DefaultEditableFeatureType;
1635
                DefaultEditableFeatureType edType =
1636
                    (DefaultEditableFeatureType) original.getEditable();
1637
                edType.clear();
1638
                edType.addAll(type);
1639
                edType.addAll(edOriginal);
1640
                if (!isEditable) {
1641
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
1642
                }
1643
            }
1644

    
1645
        }
1646

    
1647
        return type;
1648
    }
1649

    
1650
    public void validateFeatures(int mode) throws DataException {
1651
        FeatureSet collection = null;
1652
        DisposableIterator iter = null;
1653
        try {
1654
            checkNotInAppendMode();
1655
            collection = this.getFeatureSet();
1656
            iter = collection.fastIterator();
1657
            long previousVersionOfUpdate = currentVersionOfUpdate();
1658
            while (iter.hasNext()) {
1659
                ((DefaultFeature) iter.next()).validate(mode);
1660
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
1661
                    throw new ConcurrentDataModificationException(getName());
1662
                }
1663
            }
1664
        } catch (Exception e) {
1665
            throw new ValidateFeaturesException(e, getName());
1666
        } finally {
1667
            dispose(iter);
1668
            dispose(collection);
1669
        }
1670
    }
1671

    
1672
    public FeatureType getDefaultFeatureType() throws DataException {
1673
        try {
1674

    
1675
            if (isEditing()) {
1676
                FeatureType auxFeatureType =
1677
                    featureTypeManager.getType(defaultFeatureType.getId());
1678
                if (auxFeatureType != null) {
1679
                    return avoidEditable(auxFeatureType);
1680
                }
1681
            }
1682
            FeatureType type = this.transforms.getDefaultFeatureType();
1683
            if (type != null) {
1684
                return avoidEditable(type);
1685
            }
1686

    
1687
            return avoidEditable(defaultFeatureType);
1688

    
1689
        } catch (Exception e) {
1690
            throw new GetFeatureTypeException(e, getName());
1691
        }
1692
    }
1693

    
1694
    private FeatureType avoidEditable(FeatureType ft) {
1695
        if (ft instanceof EditableFeatureType) {
1696
            return ((EditableFeatureType) ft).getNotEditableCopy();
1697
        } else {
1698
            return ft;
1699
        }
1700
    }
1701

    
1702
    public FeatureType getFeatureType(String featureTypeId)
1703
        throws DataException {
1704
        if (featureTypeId == null) {
1705
            return this.getDefaultFeatureType();
1706
        }
1707
        try {
1708
            if (isEditing()) {
1709
                FeatureType auxFeatureType =
1710
                    featureTypeManager.getType(featureTypeId);
1711
                if (auxFeatureType != null) {
1712
                    return auxFeatureType;
1713
                }
1714
            }
1715
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
1716
            if (type != null) {
1717
                return type;
1718
            }
1719
            Iterator iter = this.featureTypes.iterator();
1720
            while (iter.hasNext()) {
1721
                type = (FeatureType) iter.next();
1722
                if (type.getId().equals(featureTypeId)) {
1723
                    return type;
1724
                }
1725
            }
1726
            return null;
1727
        } catch (Exception e) {
1728
            throw new GetFeatureTypeException(e, getName());
1729
        }
1730
    }
1731

    
1732
    public FeatureType getProviderDefaultFeatureType() {
1733
        return defaultFeatureType;
1734
    }
1735

    
1736
    public List getFeatureTypes() throws DataException {
1737
        try {
1738
            List types;
1739
            if (isEditing()) {
1740
                types = new ArrayList();
1741
                Iterator it = featureTypes.iterator();
1742
                while (it.hasNext()) {
1743
                    FeatureType type = (FeatureType) it.next();
1744
                    FeatureType typeaux =
1745
                        featureTypeManager.getType(type.getId());
1746
                    if (typeaux != null) {
1747
                        types.add(typeaux);
1748
                    } else {
1749
                        types.add(type);
1750
                    }
1751
                }
1752
                it = featureTypeManager.newsIterator();
1753
                while (it.hasNext()) {
1754
                    FeatureType type = (FeatureType) it.next();
1755
                    types.add(type);
1756
                }
1757
            } else {
1758
                types = this.transforms.getFeatureTypes();
1759
                if (types == null) {
1760
                    types = featureTypes;
1761
                }
1762
            }
1763
            return Collections.unmodifiableList(types);
1764
        } catch (Exception e) {
1765
            throw new GetFeatureTypeException(e, getName());
1766
        }
1767
    }
1768

    
1769
    public List getProviderFeatureTypes() throws DataException {
1770
        return Collections.unmodifiableList(this.featureTypes);
1771
    }
1772

    
1773
    public Feature createFeature(FeatureProvider data) throws DataException {
1774
        DefaultFeature feature = new DefaultFeature(this, data);
1775
        return feature;
1776
    }
1777

    
1778
    public Feature createFeature(FeatureProvider data, FeatureType type)
1779
        throws DataException {
1780
        // FIXME: falta por implementar
1781
        // Comprobar si es un subtipo del feature de data
1782
        // y construir un feature usando el subtipo.
1783
        // Probablemente requiera generar una copia del data.
1784
        throw new NotYetImplemented();
1785
    }
1786

    
1787
    public EditableFeature createNewFeature(FeatureType type,
1788
        Feature defaultValues) throws DataException {
1789
        try {
1790
            FeatureProvider data = createNewFeatureProvider(type);
1791
            DefaultEditableFeature feature =
1792
                new DefaultEditableFeature(this, data);
1793
            feature.initializeValues(defaultValues);
1794
            data.setNew(true);
1795

    
1796
            return feature;
1797
        } catch (Exception e) {
1798
            throw new CreateFeatureException(e, getName());
1799
        }
1800
    }
1801

    
1802
    private FeatureProvider createNewFeatureProvider(FeatureType type)
1803
        throws DataException {
1804
        type = this.fixFeatureType((DefaultFeatureType) type);
1805
        FeatureProvider data = this.provider.createFeatureProvider(type);
1806
        data.setNew(true);
1807
        if (type.hasOID() && (data.getOID() == null)) {
1808
            data.setOID(this.provider.createNewOID());
1809
        } else {
1810
            data.setOID(this.getTemporalOID());
1811
        }
1812
        return data;
1813

    
1814
    }
1815

    
1816
    public EditableFeature createNewFeature(FeatureType type,
1817
        boolean defaultValues) throws DataException {
1818
        try {
1819
            FeatureProvider data = createNewFeatureProvider(type);
1820
            DefaultEditableFeature feature =
1821
                new DefaultEditableFeature(this, data);
1822
            if (defaultValues) {
1823
                feature.initializeValues();
1824
            }
1825
            return feature;
1826
        } catch (Exception e) {
1827
            throw new CreateFeatureException(e, getName());
1828
        }
1829
    }
1830

    
1831
    public EditableFeature createNewFeature(boolean defaultValues)
1832
        throws DataException {
1833
        return this.createNewFeature(this.getDefaultFeatureType(),
1834
            defaultValues);
1835
    }
1836

    
1837
    public EditableFeature createNewFeature() throws DataException {
1838
        return this.createNewFeature(this.getDefaultFeatureType(), true);
1839
    }
1840

    
1841
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
1842
        FeatureType ft = this.getDefaultFeatureType();
1843
        EditableFeature f = this.createNewFeature(ft, false);
1844
        Iterator it = ft.iterator();
1845
        while(it.hasNext()) {
1846
            FeatureAttributeDescriptor desc = (FeatureAttributeDescriptor) it.next();
1847
            try {
1848
                f.set(desc.getName(), defaultValues.get(desc.getName()));
1849
            } catch(Throwable th) {
1850
                // Ignore
1851
            }
1852
        }
1853
        return f;
1854
    }
1855

    
1856
    public EditableFeatureType createFeatureType() {
1857
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType();
1858
        return ftype;
1859
    }
1860

    
1861
    public EditableFeatureType createFeatureType(String id) {
1862
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(id);
1863
        return ftype;
1864
    }
1865

    
1866
    //
1867
    // ====================================================================
1868
    // Index related methods
1869
    //
1870

    
1871
    public FeatureIndexes getIndexes() {
1872
        return this.indexes;
1873
    }
1874

    
1875
    public FeatureIndex createIndex(FeatureType featureType,
1876
        String attributeName, String indexName) throws DataException {
1877
        return createIndex(null, featureType, attributeName, indexName);
1878
    }
1879

    
1880
    public FeatureIndex createIndex(String indexTypeName,
1881
        FeatureType featureType, String attributeName, String indexName)
1882
        throws DataException {
1883

    
1884
        return createIndex(indexTypeName, featureType, attributeName,
1885
            indexName, false, null);
1886
    }
1887

    
1888
    public FeatureIndex createIndex(FeatureType featureType,
1889
        String attributeName, String indexName, Observer observer)
1890
        throws DataException {
1891
        return createIndex(null, featureType, attributeName, indexName,
1892
            observer);
1893
    }
1894

    
1895
    public FeatureIndex createIndex(String indexTypeName,
1896
        FeatureType featureType, String attributeName, String indexName,
1897
        final Observer observer) throws DataException {
1898

    
1899
        return createIndex(indexTypeName, featureType, attributeName,
1900
            indexName, true, observer);
1901
    }
1902

    
1903
    private FeatureIndex createIndex(String indexTypeName,
1904
        FeatureType featureType, String attributeName, String indexName,
1905
        boolean background, final Observer observer) throws DataException {
1906

    
1907
        checkNotInAppendMode();
1908
        FeatureIndexProviderServices index = null;
1909
        index =
1910
            dataManager.createFeatureIndexProvider(indexTypeName, this,
1911
                featureType, indexName,
1912
                featureType.getAttributeDescriptor(attributeName));
1913

    
1914
        try {
1915
            index.fill(background, observer);
1916
        } catch (FeatureIndexException e) {
1917
            throw new InitializeException(index.getName(), e);
1918
        }
1919

    
1920
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
1921
        return index;
1922
    }
1923

    
1924
    //
1925
    // ====================================================================
1926
    // Transforms related methods
1927
    //
1928

    
1929
    public FeatureStoreTransforms getTransforms() {
1930
        return this.transforms;
1931
    }
1932

    
1933
    public FeatureQuery createFeatureQuery() {
1934
        return new DefaultFeatureQuery();
1935
    }
1936

    
1937
    public DataQuery createQuery() {
1938
        return createFeatureQuery();
1939
    }
1940

    
1941
    //
1942
    // ====================================================================
1943
    // UndoRedo related methods
1944
    //
1945

    
1946
    public boolean canRedo() {
1947
        return commands.canRedo();
1948
    }
1949

    
1950
    public boolean canUndo() {
1951
        return commands.canUndo();
1952
    }
1953

    
1954
    public void redo(int num) throws RedoException {
1955
        for (int i = 0; i < num; i++) {
1956
            redo();
1957
        }
1958
    }
1959

    
1960
    public void undo(int num) throws UndoException {
1961
        for (int i = 0; i < num; i++) {
1962
            undo();
1963
        }
1964
    }
1965

    
1966
    //
1967
    // ====================================================================
1968
    // Metadata related methods
1969
    //
1970

    
1971
    public Object getMetadataID() {
1972
        return this.provider.getSourceId();
1973
    }
1974

    
1975
    public void delegate(DynObject dynObject) {
1976
        this.metadata.delegate(dynObject);
1977
    }
1978

    
1979
    public DynClass getDynClass() {
1980
        return this.metadata.getDynClass();
1981
    }
1982

    
1983
        public Object getDynValue(String name) throws DynFieldNotFoundException {
1984
                if( this.transforms.hasDynValue(name) ) {
1985
                        return this.transforms.getDynValue(name);
1986
                }
1987
                if (this.metadata.hasDynValue(name)) {
1988
                        return this.metadata.getDynValue(name);
1989
                }
1990
                if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
1991
                        return this.provider.getProviderName();
1992
                } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
1993
                        return this.provider.getSourceId();
1994
                } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
1995
                        try {
1996
                                return this.getDefaultFeatureType();
1997
                        } catch (DataException e) {
1998
                                return null;
1999
                        }
2000
                }
2001
                return this.metadata.getDynValue(name);
2002
        }
2003

    
2004
    public boolean hasDynValue(String name) {
2005
                if( this.transforms.hasDynValue(name) ) {
2006
                        return true;
2007
                }
2008
        return this.metadata.hasDynValue(name);
2009
    }
2010

    
2011
    public void implement(DynClass dynClass) {
2012
        this.metadata.implement(dynClass);
2013
    }
2014

    
2015
    public Object invokeDynMethod(String name, DynObject context)
2016
        throws DynMethodException {
2017
        return this.metadata.invokeDynMethod(this, name, context);
2018
    }
2019

    
2020
    public Object invokeDynMethod(int code, DynObject context)
2021
        throws DynMethodException {
2022
        return this.metadata.invokeDynMethod(this, code, context);
2023
    }
2024

    
2025
    public void setDynValue(String name, Object value)
2026
        throws DynFieldNotFoundException {
2027
                if( this.transforms.hasDynValue(name) ) {
2028
                        this.transforms.setDynValue(name, value);
2029
                        return;
2030
                }
2031
        this.metadata.setDynValue(name, value);
2032

    
2033
    }
2034

    
2035
    /*
2036
     * (non-Javadoc)
2037
     *
2038
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2039
     */
2040
    public Set getMetadataChildren() {
2041
        return this.metadataChildren;
2042
    }
2043

    
2044
    /*
2045
     * (non-Javadoc)
2046
     *
2047
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2048
     */
2049
    public String getMetadataName() {
2050
        return this.provider.getProviderName();
2051
    }
2052

    
2053
    public FeatureTypeManager getFeatureTypeManager() {
2054
        return this.featureTypeManager;
2055
    }
2056

    
2057
    public long getFeatureCount() throws DataException {
2058
        if (featureCount == null) {
2059
            featureCount = new Long(this.provider.getFeatureCount());
2060
        }
2061
        if (this.isEditing() && !this.isAppending()) {
2062
            return featureCount.longValue()
2063
                - this.featureManager.getDeltaSize();
2064
        }
2065
        return featureCount.longValue();
2066
    }
2067

    
2068
    private Long getTemporalOID() {
2069
        return new Long(this.temporalOid++);
2070
    }
2071

    
2072
    public FeatureType getProviderFeatureType(String featureTypeId) {
2073
        if (featureTypeId == null) {
2074
            return this.defaultFeatureType;
2075
        }
2076
        FeatureType type;
2077
        Iterator iter = this.featureTypes.iterator();
2078
        while (iter.hasNext()) {
2079
            type = (FeatureType) iter.next();
2080
            if (type.getId().equals(featureTypeId)) {
2081
                return type;
2082
            }
2083
        }
2084
        return null;
2085
    }
2086

    
2087
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2088
        return ((DefaultFeature) feature).getData();
2089
    }
2090

    
2091
    public DataStore getStore() {
2092
        return this;
2093
    }
2094

    
2095
    public FeatureStore getFeatureStore() {
2096
        return this;
2097
    }
2098

    
2099
    public void createCache(String name, DynObject parameters)
2100
        throws DataException {
2101
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2102
        if (cache == null) {
2103
            throw new CreateException("FeaureCacheProvider", null);
2104
        }
2105
        cache.apply(this, provider);
2106
        provider = cache;
2107

    
2108
        featureCount = null;
2109
    }
2110

    
2111
    public FeatureCache getCache() {
2112
        return cache;
2113
    }
2114

    
2115
    public void clear() {
2116
        if (metadata != null) {
2117
            metadata.clear();
2118
        }
2119
    }
2120

    
2121
    public String getName() {
2122
        return this.provider.getName();
2123
    }
2124

    
2125
    public String getFullName() {
2126
        try {
2127
            return this.provider.getFullName();
2128
        } catch(Throwable th) {
2129
            return null;
2130
        }
2131
    }
2132

    
2133
    public String getProviderName() {
2134
        return this.provider.getProviderName();
2135
    }
2136

    
2137
    public boolean isKnownEnvelope() {
2138
        return this.provider.isKnownEnvelope();
2139
    }
2140

    
2141
    public boolean hasRetrievedFeaturesLimit() {
2142
        return this.provider.hasRetrievedFeaturesLimit();
2143
    }
2144

    
2145
    public int getRetrievedFeaturesLimit() {
2146
        return this.provider.getRetrievedFeaturesLimit();
2147
    }
2148

    
2149
    public Interval getInterval() {
2150
        return this.provider.getInterval();
2151
    }
2152

    
2153
    public Collection getTimes() {
2154
        return this.provider.getTimes();
2155
    }
2156

    
2157
    public Collection getTimes(Interval interval) {
2158
        return this.provider.getTimes(interval);
2159
    }
2160

    
2161
    /* (non-Javadoc)
2162
     * @see java.lang.Object#clone()
2163
     */
2164
    public Object clone() throws CloneNotSupportedException {
2165

    
2166
        DataStoreParameters dsp = getParameters();
2167

    
2168
        DefaultFeatureStore cloned_store = null;
2169

    
2170
        try {
2171
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2172
                openStore(this.getProviderName(), dsp);
2173
            if (transforms != null) {
2174
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2175
                cloned_store.transforms.setStoreForClone(cloned_store);
2176
            }
2177
        } catch (Exception e) {
2178
            throw new CloneException(e);
2179
        }
2180
        return cloned_store;
2181

    
2182
    }
2183

    
2184
    public Feature getFeature(DynObject dynobject) {
2185
        if (dynobject instanceof DynObjectFeatureFacade){
2186
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2187
            return f;
2188
        }
2189
        return null;
2190
    }
2191
    
2192
    public Iterator iterator() {
2193
        try {
2194
            return this.getFeatureSet().fastIterator();
2195
        } catch (DataException ex) {
2196
            throw new RuntimeException(ex);
2197
        }
2198
    }
2199
}