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

History | View | Annotate | Download (77.7 KB)

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

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

    
27
import org.gvsig.fmap.dal.feature.spi.SQLBuilderBase;
28
import java.util.ArrayList;
29
import java.util.Collection;
30
import java.util.Collections;
31
import java.util.HashMap;
32
import java.util.HashSet;
33
import java.util.Iterator;
34
import java.util.List;
35
import java.util.Map;
36
import java.util.Map.Entry;
37
import java.util.Set;
38
import java.util.logging.Level;
39

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

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

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

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

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

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

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

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

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

    
184
    private DefaultDataManager dataManager = null;
185

    
186
    private FeatureStoreProvider provider = null;
187

    
188
    private DefaultFeatureIndexes indexes;
189

    
190
    private DefaultFeatureStoreTransforms transforms;
191

    
192
    DelegatedDynObject metadata;
193

    
194
    private Set metadataChildren;
195

    
196
    private Long featureCount = null;
197

    
198
    private long temporalOid = 0;
199

    
200
    private FeatureCacheProvider cache;
201

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

    
211
    public DefaultFeatureStore() {
212

    
213
    }
214

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

    
219
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
220

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

    
226
        this.dataManager = (DefaultDataManager) dataManager;
227

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

    
236
    }
237

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
450
        }
451

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

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

    
459
    }
460

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

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

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

    
520
                }
521

    
522
            }
523

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

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

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

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

    
556
    }
557

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
699
    @Override
700
    public void notifyChange(FeatureStoreNotification storeNotification) {
701
        try {
702
            delegateObservable.notifyObservers(storeNotification);
703
        } catch (Throwable ex) {
704
            LOG.warn("Problems notifying changes in the store '"+this.getName()+" ("+storeNotification.getType()+").",ex);
705
        }
706
    }
707

    
708
    @Override
709
    public void notifyChange(String notification) {
710
        if (delegateObservable != null) {
711
            notifyChange(new DefaultFeatureStoreNotification(this, notification));
712
        }
713

    
714
    }
715

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

    
727
    public void notifyChange(String notification, Feature feature) {
728
        notifyChange(new DefaultFeatureStoreNotification(this, notification,
729
            feature));
730
    }
731

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

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

    
742
    @Override
743
    public void notifyChange(String notification, Resource resource) {
744
        notifyChange(new DefaultFeatureStoreNotification(this,
745
            DataStoreNotification.RESOURCE_CHANGED));
746
    }
747

    
748
    //
749
    // ====================================================================
750
    // Gestion de bloqueos
751
    //
752

    
753
    public boolean isLocksSupported() {
754
        return this.provider.isLocksSupported();
755
    }
756

    
757
    public FeatureLocks getLocks() throws DataException {
758
        if (!this.provider.isLocksSupported()) {
759
            LOG.warn("Locks not supported");
760
            return null;
761
        }
762
        if (locks == null) {
763
            this.locks = this.provider.createFeatureLocks();
764
        }
765
        return locks;
766
    }
767

    
768
    //
769
    // ====================================================================
770
    // Interface Observable
771
    //
772

    
773
    public void disableNotifications() {
774
        this.delegateObservable.disableNotifications();
775

    
776
    }
777

    
778
    public void enableNotifications() {
779
        this.delegateObservable.enableNotifications();
780
    }
781

    
782
    public void beginComplexNotification() {
783
        this.delegateObservable.beginComplexNotification();
784

    
785
    }
786

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

    
790
    }
791

    
792
    public void addObserver(Observer observer) {
793
        if (delegateObservable != null) {
794
            this.delegateObservable.addObserver(observer);
795
        }
796
    }
797

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

    
804
    public void deleteObservers() {
805
        this.delegateObservable.deleteObservers();
806

    
807
    }
808

    
809
    //
810
    // ====================================================================
811
    // Interface Observer
812
    //
813
    // Usado para observar:
814
    // - su seleccion
815
    // - sus bloqueos
816
    // - sus recursos
817
    //
818

    
819
    public void update(Observable observable, Object notification) {
820
        if (observable instanceof FeatureSet) {
821
            if (observable == this.selection) {
822
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
823
            } else
824
                if (observable == this.locks) {
825
                    this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
826
                }
827

    
828
        } else
829
            if (observable instanceof FeatureStoreProvider) {
830
                if (observable == this.provider) {
831

    
832
                }
833

    
834
            }
835
    }
836

    
837
    //
838
    // ====================================================================
839
    // Edicion
840
    //
841

    
842
    private void newVersionOfUpdate() {
843
        this.versionOfUpdate++;
844
    }
845

    
846
    private long currentVersionOfUpdate() {
847
        return this.versionOfUpdate;
848
    }
849

    
850
    private void checkInEditingMode() throws NeedEditingModeException {
851
        if (mode != MODE_FULLEDIT) {
852
            throw new NeedEditingModeException(this.getName());
853
        }
854
    }
855

    
856
    private void checkNotInAppendMode() throws IllegalStateException {
857
        if (mode == MODE_APPEND) {
858
                        throw new IllegalStateException("Error: store "
859
                                        + this.getFullName() + " is in append mode");
860
        }
861
    }
862

    
863
    private void checkIsOwnFeature(Feature feature)
864
        throws IllegalFeatureException {
865
        if (((DefaultFeature) feature).getStore() != this) {
866
            throw new IllegalFeatureException(this.getName());
867
        }
868
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
869
        // fixFeatureType((DefaultFeatureType) feature.getType());
870
    }
871

    
872
    private void exitEditingMode() {
873
        if (commands != null) {
874
            commands.clear();
875
            commands = null;
876
        }
877

    
878
        if (featureTypeManager != null) {
879
            featureTypeManager.dispose();
880
            featureTypeManager = null;
881

    
882
        }
883

    
884
        // TODO implementar un dispose para estos dos
885
        featureManager = null;
886
        spatialManager = null;
887

    
888
        featureCount = null;
889

    
890
        mode = MODE_QUERY;
891
        hasStrongChanges = true; // Lo deja a true por si las moscas
892
        hasInserts = true;
893
    }
894

    
895
    synchronized public void edit() throws DataException {
896
        edit(MODE_FULLEDIT);
897
    }
898

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

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

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

    
950
    private void invalidateIndexes() {
951
        setIndexesValidStatus(false);
952
    }
953

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

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

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

    
994
    private void disposeIndexes() {
995
        FeatureIndexes indexes = getIndexes();
996
        LOG.debug("Disposing indexes: {}", indexes);
997
        for (Iterator iterator = indexes.iterator(); iterator.hasNext();) {
998
            FeatureIndex index = (FeatureIndex) iterator.next();
999
            if (index instanceof FeatureIndexProviderServices) {
1000
                FeatureIndexProviderServices indexServices =
1001
                    (FeatureIndexProviderServices) index;
1002
                indexServices.dispose();
1003
            }
1004
        }
1005
    }
1006

    
1007
    public boolean isEditing() {
1008
        return mode == MODE_FULLEDIT;
1009
    }
1010

    
1011
    public boolean isAppending() {
1012
        return mode == MODE_APPEND;
1013
    }
1014

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

    
1026
            FeatureType oldt = type.getSource().getCopy();
1027
            FeatureType newt = type.getCopy();
1028
            commands.update(newt, oldt);
1029

    
1030
            if (((DefaultEditableFeatureType) type).hasStrongChanges()) {
1031
                hasStrongChanges = true;
1032
            }
1033
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1034
        } catch (Exception e) {
1035
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1036
        }
1037
    }
1038

    
1039
    public void delete(Feature feature) throws DataException {
1040
        this.commands.delete(feature);
1041
    }
1042

    
1043
    synchronized public void doDelete(Feature feature) throws DataException {
1044
        try {
1045
            checkInEditingMode();
1046
            checkIsOwnFeature(feature);
1047
            if (feature instanceof EditableFeature) {
1048
                throw new StoreDeleteEditableFeatureException(getName());
1049
            }
1050
            notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature);
1051

    
1052
            //Update the featureManager and the spatialManager
1053
            featureManager.delete(feature.getReference());
1054
            spatialManager.deleteFeature(feature);
1055

    
1056
            newVersionOfUpdate();
1057
            hasStrongChanges = true;
1058
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1059
        } catch (Exception e) {
1060
            throw new StoreDeleteFeatureException(e, this.getName());
1061
        }
1062
    }
1063

    
1064
    private static EditableFeature lastChangedFeature = null;
1065

    
1066
    public synchronized void insert(EditableFeature feature)
1067
        throws DataException {
1068
        LOG.debug("In editing mode {}, insert feature: {}", new Integer(mode),
1069
            feature);
1070
        try {
1071
            switch (mode) {
1072
            case MODE_QUERY:
1073
                throw new NeedEditingModeException(this.getName());
1074

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

    
1089
            case MODE_FULLEDIT:
1090
                if (feature.getSource() != null) {
1091
                    throw new NoNewFeatureInsertException(this.getName());
1092
                }
1093
                commands.insert(feature);
1094
            }
1095
        } catch (Exception e) {
1096
            throw new StoreInsertFeatureException(e, this.getName());
1097
        }
1098
    }
1099

    
1100
    synchronized public void doInsert(EditableFeature feature)
1101
        throws DataException {
1102
        checkIsOwnFeature(feature);
1103

    
1104
        waitForIndexes();
1105

    
1106
        notifyChange(FeatureStoreNotification.BEFORE_INSERT, 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
        //Update the featureManager and the spatialManager
1115
        ((DefaultEditableFeature) feature).setInserted(true);
1116
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1117

    
1118

    
1119
        featureManager.add(newFeature);
1120
        spatialManager.insertFeature(newFeature);
1121

    
1122
        hasStrongChanges = true;
1123
        hasInserts = true;
1124
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1125
    }
1126

    
1127
    public void update(EditableFeature feature)
1128
    throws DataException {
1129
        if ((feature).getSource() == null) {
1130
            insert(feature);
1131
            return;
1132
        }
1133
        commands.update(feature, feature.getSource());
1134
    }
1135

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

    
1150
            //Update the featureManager and the spatialManager
1151
            Feature newf = feature.getNotEditableCopy();
1152
            featureManager.update(newf, oldFeature);
1153
            spatialManager.updateFeature(newf, oldFeature);
1154

    
1155
            hasStrongChanges = true;
1156
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1157
        } catch (Exception e) {
1158
            throw new StoreUpdateFeatureException(e, this.getName());
1159
        }
1160
    }
1161

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

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

    
1190
    public List getRedoInfos() {
1191
        if (isEditing() && (commands != null)) {
1192
            return commands.getRedoInfos();
1193
        } else {
1194
            return null;
1195
        }
1196
    }
1197

    
1198
    public List getUndoInfos() {
1199
        if (isEditing() && (commands != null)) {
1200
            return commands.getUndoInfos();
1201
        } else {
1202
            return null;
1203
        }
1204
    }
1205

    
1206
    public synchronized FeatureCommandsStack getCommandsStack()
1207
        throws DataException {
1208
        checkInEditingMode();
1209
        return commands;
1210
    }
1211

    
1212
    synchronized public void cancelEditing() throws DataException {
1213
        spatialManager.cancelModifies();
1214
        try {
1215
            checkInEditingMode();
1216

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

    
1233
    synchronized public void finishEditing() throws DataException {
1234
        LOG.debug("finish editing of mode: {}", new Integer(mode));
1235
        try {
1236

    
1237
            /*
1238
             * Selection needs to be cleared when editing stops
1239
             * to prevent conflicts with selection remaining from
1240
             * editing mode.
1241
             */
1242
//            ((FeatureSelection) this.getSelection()).deselectAll();
1243

    
1244
            switch (mode) {
1245
            case MODE_QUERY:
1246
                throw new NeedEditingModeException(this.getName());
1247

    
1248
            case MODE_APPEND:
1249
                ((FeatureSelection) this.getSelection()).deselectAll();
1250
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1251
                provider.endAppend();
1252
                exitEditingMode();
1253
                updateIndexes();
1254
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1255
                break;
1256

    
1257
            case MODE_FULLEDIT:
1258
                if (hasStrongChanges && !this.allowWrite()) {
1259
                    throw new WriteNotAllowedException(getName());
1260
                }
1261

    
1262
                if(featureManager.isSelectionCompromised()) {
1263
                    ((FeatureSelection) this.getSelection()).deselectAll();
1264
                };
1265

    
1266
                notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING);
1267
                if (hasStrongChanges) {
1268
                    validateFeatures(Feature.FINISH_EDITING);
1269

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

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

    
1309
        case MODE_APPEND:
1310
          this.provider.endAppend();
1311
          exitEditingMode();
1312
          invalidateIndexes();
1313
          this.provider.beginAppend();
1314
          hasInserts = false;
1315
          break;
1316

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

    
1336
          commands =
1337
            new DefaultFeatureCommandsStack(this, featureManager,
1338
              spatialManager, featureTypeManager);
1339
          featureCount = null;
1340
          hasStrongChanges = false;
1341
          hasInserts = false;
1342
          break;
1343
        }
1344
      } catch (Exception e) {
1345
        throw new FinishEditingException(e);
1346
      }
1347
    }
1348

    
1349
    synchronized public boolean canCommitChanges() throws DataException {
1350
        if ( !this.allowWrite()) {
1351
                return false;
1352
        }
1353
            switch (mode) {
1354
            default:
1355
        case MODE_QUERY:
1356
                return false;
1357

    
1358
        case MODE_APPEND:
1359
                return true;
1360

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

    
1375
    public void beginEditingGroup(String description)
1376
        throws NeedEditingModeException {
1377
        checkInEditingMode();
1378
        commands.startComplex(description);
1379
    }
1380

    
1381
    public void endEditingGroup() throws NeedEditingModeException {
1382
        checkInEditingMode();
1383
        commands.endComplex();
1384
    }
1385

    
1386
    public boolean isAppendModeSupported() {
1387
        return this.provider.supportsAppendMode();
1388
    }
1389

    
1390
    public void export(DataServerExplorer explorer, String provider,
1391
        NewFeatureStoreParameters params) throws DataException {
1392

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

    
1407
            }
1408
            explorer.add(provider, params, true);
1409

    
1410
            DataManager manager = DALLocator.getDataManager();
1411
            target = (FeatureStore) manager.openStore(provider, params);
1412
            FeatureType targetType = target.getDefaultFeatureType();
1413

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

    
1445
    //
1446
    // ====================================================================
1447
    // Obtencion de datos
1448
    // getDataCollection, getFeatureCollection
1449
    //
1450

    
1451
    public DataSet getDataSet() throws DataException {
1452
        checkNotInAppendMode();
1453
        FeatureQuery query =
1454
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1455
        return new DefaultFeatureSet(this, query);
1456
    }
1457

    
1458
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1459
        checkNotInAppendMode();
1460
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1461
    }
1462

    
1463
    public void getDataSet(Observer observer) throws DataException {
1464
        checkNotInAppendMode();
1465
        this.getFeatureSet(null, observer);
1466
    }
1467

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

    
1474
    @Override
1475
    public FeatureSet getFeatureSet() throws DataException {
1476
        return this.getFeatureSet((FeatureQuery)null);
1477
    }
1478

    
1479
    @Override
1480
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1481
        throws DataException {
1482
        checkNotInAppendMode();
1483
        if( featureQuery==null ) {
1484
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1485
        }
1486
        return new DefaultFeatureSet(this, featureQuery);
1487
    }
1488

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

    
1499
    @Override
1500
    public List<Feature> getFeatures() {
1501
        return this.getFeatures(null, 500);
1502
    }
1503
    
1504
    public void accept(Visitor visitor) throws BaseException {
1505
        FeatureSet set = getFeatureSet();
1506
        try {
1507
            set.accept(visitor);
1508
        } finally {
1509
            set.dispose();
1510
        }
1511
    }
1512

    
1513
    public void accept(Visitor visitor, DataQuery dataQuery)
1514
        throws BaseException {
1515
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
1516
        try {
1517
            set.accept(visitor);
1518
        } finally {
1519
            set.dispose();
1520
        }
1521
    }
1522

    
1523
    public FeatureType getFeatureType(FeatureQuery featureQuery)
1524
        throws DataException {
1525
        DefaultFeatureType fType =
1526
            (DefaultFeatureType) this.getFeatureType(featureQuery
1527
                .getFeatureTypeId());
1528
        if( featureQuery.hasAttributeNames() || featureQuery.hasConstantsAttributeNames() ) {
1529
            return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames() );
1530
        }
1531
        return fType;
1532
    }
1533

    
1534
    public void getFeatureSet(Observer observer) throws DataException {
1535
        checkNotInAppendMode();
1536
        this.getFeatureSet(null, observer);
1537
    }
1538

    
1539
    public void getFeatureSet(FeatureQuery query, Observer observer)
1540
        throws DataException {
1541
        class LoadInBackGround implements Runnable {
1542

    
1543
            private FeatureStore store;
1544
            private FeatureQuery query;
1545
            private Observer observer;
1546

    
1547
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
1548
                Observer observer) {
1549
                this.store = store;
1550
                this.query = query;
1551
                this.observer = observer;
1552
            }
1553

    
1554
            void notify(FeatureStoreNotification theNotification) {
1555
                observer.update(store, theNotification);
1556
                return;
1557
            }
1558

    
1559
            public void run() {
1560
                FeatureSet set = null;
1561
                try {
1562
                    set = store.getFeatureSet(query);
1563
                    notify(new DefaultFeatureStoreNotification(store,
1564
                        FeatureStoreNotification.LOAD_FINISHED, set));
1565
                } catch (Exception e) {
1566
                    notify(new DefaultFeatureStoreNotification(store,
1567
                        FeatureStoreNotification.LOAD_FINISHED, e));
1568
                } finally {
1569
                    dispose(set);
1570
                }
1571
            }
1572
        }
1573

    
1574
        checkNotInAppendMode();
1575
        if (query == null) {
1576
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
1577
        }
1578
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
1579
        Thread thread = new Thread(task, "Load Feature Set in background");
1580
        thread.start();
1581
    }
1582

    
1583
    public Feature getFeatureByReference(FeatureReference reference)
1584
        throws DataException {
1585
        checkNotInAppendMode();
1586
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
1587
        FeatureType featureType;
1588
        if (ref.getFeatureTypeId() == null) {
1589
            featureType = this.getDefaultFeatureType();
1590
        } else {
1591
            featureType = this.getFeatureType(ref.getFeatureTypeId());
1592
        }
1593
        return this.getFeatureByReference(reference, featureType);
1594
    }
1595

    
1596
    public Feature getFeatureByReference(FeatureReference reference,
1597
        FeatureType featureType) throws DataException {
1598
        checkNotInAppendMode();
1599
        featureType = fixFeatureType((DefaultFeatureType) featureType);
1600
        if (this.mode == MODE_FULLEDIT) {
1601
            Feature f = featureManager.get(reference, this, featureType);
1602
            if (f != null) {
1603
                return f;
1604
            }
1605
        }
1606

    
1607
        FeatureType sourceFeatureType = featureType;
1608
        if (!this.transforms.isEmpty()) {
1609
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
1610
        }
1611
        // TODO comprobar que el id es de este store
1612

    
1613
        DefaultFeature feature =
1614
            new DefaultFeature(this,
1615
                this.provider.getFeatureProviderByReference(
1616
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
1617

    
1618
        if (!this.transforms.isEmpty()) {
1619
            return this.transforms.applyTransform(feature, featureType);
1620
        }
1621
        return feature;
1622
    }
1623

    
1624
    //
1625
    // ====================================================================
1626
    // Gestion de features
1627
    //
1628

    
1629
    private FeatureType fixFeatureType(DefaultFeatureType type)
1630
        throws DataException {
1631
        FeatureType original = this.getDefaultFeatureType();
1632

    
1633
        if ((type == null) || type.equals(original)) {
1634
            return original;
1635
        } else {
1636
            if (!type.isSubtypeOf(original)) {
1637
                Iterator iter = this.getFeatureTypes().iterator();
1638
                FeatureType tmpType;
1639
                boolean found = false;
1640
                while (iter.hasNext()) {
1641
                    tmpType = (FeatureType) iter.next();
1642
                    if (type.equals(tmpType)) {
1643
                        return type;
1644

    
1645
                    } else
1646
                        if (type.isSubtypeOf(tmpType)) {
1647
                            found = true;
1648
                            original = tmpType;
1649
                            break;
1650
                        }
1651

    
1652
                }
1653
                if (!found) {
1654
                    throw new IllegalFeatureTypeException(getName());
1655
                }
1656
            }
1657
        }
1658

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

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

    
1690
            // add missing pk attributes if any
1691
            if (edOriginal.size() > 0) {
1692
                boolean isEditable = type instanceof DefaultEditableFeatureType;
1693
                DefaultEditableFeatureType edType =
1694
                    (DefaultEditableFeatureType) original.getEditable();
1695
                edType.clear();
1696
                edType.addAll(type);
1697
                edType.addAll(edOriginal);
1698
                if (!isEditable) {
1699
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
1700
                }
1701
            }
1702

    
1703
        }
1704

    
1705
        return type;
1706
    }
1707

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

    
1730
    public FeatureType getDefaultFeatureType() throws DataException {
1731
        try {
1732

    
1733
            if (isEditing()) {
1734
                FeatureType auxFeatureType =
1735
                    featureTypeManager.getType(defaultFeatureType.getId());
1736
                if (auxFeatureType != null) {
1737
                    return avoidEditable(auxFeatureType);
1738
                }
1739
            }
1740
            FeatureType type = this.transforms.getDefaultFeatureType();
1741
            if (type != null) {
1742
                return avoidEditable(type);
1743
            }
1744

    
1745
            return avoidEditable(defaultFeatureType);
1746

    
1747
        } catch (Exception e) {
1748
            throw new GetFeatureTypeException(e, getName());
1749
        }
1750
    }
1751

    
1752
    private FeatureType avoidEditable(FeatureType ft) {
1753
        if (ft instanceof EditableFeatureType) {
1754
            return ((EditableFeatureType) ft).getNotEditableCopy();
1755
        } else {
1756
            return ft;
1757
        }
1758
    }
1759

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

    
1790
    public FeatureType getProviderDefaultFeatureType() {
1791
        return defaultFeatureType;
1792
    }
1793

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

    
1827
    public List getProviderFeatureTypes() throws DataException {
1828
        return Collections.unmodifiableList(this.featureTypes);
1829
    }
1830

    
1831
    public Feature createFeature(FeatureProvider data) throws DataException {
1832
        DefaultFeature feature = new DefaultFeature(this, data);
1833
        return feature;
1834
    }
1835

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

    
1845
    public EditableFeature createNewFeature(FeatureType type,
1846
        Feature defaultValues) throws DataException {
1847
        try {
1848
            FeatureProvider data = createNewFeatureProvider(type);
1849
            DefaultEditableFeature feature =
1850
                new DefaultEditableFeature(this, data);
1851
            feature.initializeValues(defaultValues);
1852
            data.setNew(true);
1853

    
1854
            return feature;
1855
        } catch (Exception e) {
1856
            throw new CreateFeatureException(e, getName());
1857
        }
1858
    }
1859

    
1860
    private FeatureProvider createNewFeatureProvider(FeatureType type)
1861
        throws DataException {
1862
        type = this.fixFeatureType((DefaultFeatureType) type);
1863
        FeatureProvider data = this.provider.createFeatureProvider(type);
1864
        data.setNew(true);
1865
        if (type.hasOID() && (data.getOID() == null)) {
1866
            data.setOID(this.provider.createNewOID());
1867
        } else {
1868
            data.setOID(this.getTemporalOID());
1869
        }
1870
        return data;
1871

    
1872
    }
1873

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

    
1889
    public EditableFeature createNewFeature(boolean defaultValues)
1890
        throws DataException {
1891
        return this.createNewFeature(this.getDefaultFeatureType(),
1892
            defaultValues);
1893
    }
1894

    
1895
    public EditableFeature createNewFeature() throws DataException {
1896
        return this.createNewFeature(this.getDefaultFeatureType(), true);
1897
    }
1898

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

    
1914
    public EditableFeatureType createFeatureType() {
1915
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType();
1916
        return ftype;
1917
    }
1918

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

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

    
1929
    public FeatureIndexes getIndexes() {
1930
        return this.indexes;
1931
    }
1932

    
1933
    public FeatureIndex createIndex(FeatureType featureType,
1934
        String attributeName, String indexName) throws DataException {
1935
        return createIndex(null, featureType, attributeName, indexName);
1936
    }
1937

    
1938
    public FeatureIndex createIndex(String indexTypeName,
1939
        FeatureType featureType, String attributeName, String indexName)
1940
        throws DataException {
1941

    
1942
        return createIndex(indexTypeName, featureType, attributeName,
1943
            indexName, false, null);
1944
    }
1945

    
1946
    public FeatureIndex createIndex(FeatureType featureType,
1947
        String attributeName, String indexName, Observer observer)
1948
        throws DataException {
1949
        return createIndex(null, featureType, attributeName, indexName,
1950
            observer);
1951
    }
1952

    
1953
    public FeatureIndex createIndex(String indexTypeName,
1954
        FeatureType featureType, String attributeName, String indexName,
1955
        final Observer observer) throws DataException {
1956

    
1957
        return createIndex(indexTypeName, featureType, attributeName,
1958
            indexName, true, observer);
1959
    }
1960

    
1961
    private FeatureIndex createIndex(String indexTypeName,
1962
        FeatureType featureType, String attributeName, String indexName,
1963
        boolean background, final Observer observer) throws DataException {
1964

    
1965
        checkNotInAppendMode();
1966
        FeatureIndexProviderServices index = null;
1967
        index =
1968
            dataManager.createFeatureIndexProvider(indexTypeName, this,
1969
                featureType, indexName,
1970
                featureType.getAttributeDescriptor(attributeName));
1971

    
1972
        try {
1973
            index.fill(background, observer);
1974
        } catch (FeatureIndexException e) {
1975
            throw new InitializeException(index.getName(), e);
1976
        }
1977

    
1978
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
1979
        return index;
1980
    }
1981

    
1982
    //
1983
    // ====================================================================
1984
    // Transforms related methods
1985
    //
1986

    
1987
    public FeatureStoreTransforms getTransforms() {
1988
        return this.transforms;
1989
    }
1990

    
1991
    public FeatureQuery createFeatureQuery() {
1992
        return new DefaultFeatureQuery();
1993
    }
1994

    
1995
    public DataQuery createQuery() {
1996
        return createFeatureQuery();
1997
    }
1998

    
1999
    //
2000
    // ====================================================================
2001
    // UndoRedo related methods
2002
    //
2003

    
2004
    public boolean canRedo() {
2005
        return commands.canRedo();
2006
    }
2007

    
2008
    public boolean canUndo() {
2009
        return commands.canUndo();
2010
    }
2011

    
2012
    public void redo(int num) throws RedoException {
2013
        for (int i = 0; i < num; i++) {
2014
            redo();
2015
        }
2016
    }
2017

    
2018
    public void undo(int num) throws UndoException {
2019
        for (int i = 0; i < num; i++) {
2020
            undo();
2021
        }
2022
    }
2023

    
2024
    //
2025
    // ====================================================================
2026
    // Metadata related methods
2027
    //
2028

    
2029
    public Object getMetadataID() {
2030
        return this.provider.getSourceId();
2031
    }
2032

    
2033
    public void delegate(DynObject dynObject) {
2034
        this.metadata.delegate(dynObject);
2035
    }
2036

    
2037
    public DynClass getDynClass() {
2038
        return this.metadata.getDynClass();
2039
    }
2040

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

    
2062
    public boolean hasDynValue(String name) {
2063
                if( this.transforms.hasDynValue(name) ) {
2064
                        return true;
2065
                }
2066
        return this.metadata.hasDynValue(name);
2067
    }
2068

    
2069
    public void implement(DynClass dynClass) {
2070
        this.metadata.implement(dynClass);
2071
    }
2072

    
2073
    public Object invokeDynMethod(String name, Object[] args)
2074
        throws DynMethodException {
2075
        return this.metadata.invokeDynMethod(this, name, args);
2076
    }
2077

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

    
2083
    public void setDynValue(String name, Object value)
2084
        throws DynFieldNotFoundException {
2085
                if( this.transforms.hasDynValue(name) ) {
2086
                        this.transforms.setDynValue(name, value);
2087
                        return;
2088
                }
2089
        this.metadata.setDynValue(name, value);
2090

    
2091
    }
2092

    
2093
    /*
2094
     * (non-Javadoc)
2095
     *
2096
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2097
     */
2098
    public Set getMetadataChildren() {
2099
        return this.metadataChildren;
2100
    }
2101

    
2102
    /*
2103
     * (non-Javadoc)
2104
     *
2105
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2106
     */
2107
    public String getMetadataName() {
2108
        return this.provider.getProviderName();
2109
    }
2110

    
2111
    public FeatureTypeManager getFeatureTypeManager() {
2112
        return this.featureTypeManager;
2113
    }
2114

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

    
2136
    private Long getTemporalOID() {
2137
        return new Long(this.temporalOid++);
2138
    }
2139

    
2140
    public FeatureType getProviderFeatureType(String featureTypeId) {
2141
        if (featureTypeId == null) {
2142
            return this.defaultFeatureType;
2143
        }
2144
        FeatureType type;
2145
        Iterator iter = this.featureTypes.iterator();
2146
        while (iter.hasNext()) {
2147
            type = (FeatureType) iter.next();
2148
            if (type.getId().equals(featureTypeId)) {
2149
                return type;
2150
            }
2151
        }
2152
        return null;
2153
    }
2154

    
2155
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2156
        return ((DefaultFeature) feature).getData();
2157
    }
2158

    
2159
    public DataStore getStore() {
2160
        return this;
2161
    }
2162

    
2163
    public FeatureStore getFeatureStore() {
2164
        return this;
2165
    }
2166

    
2167
    public void createCache(String name, DynObject parameters)
2168
        throws DataException {
2169
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2170
        if (cache == null) {
2171
            throw new CreateException("FeaureCacheProvider", null);
2172
        }
2173
        cache.apply(this, provider);
2174
        provider = cache;
2175

    
2176
        featureCount = null;
2177
    }
2178

    
2179
    public FeatureCache getCache() {
2180
        return cache;
2181
    }
2182

    
2183
    public void clear() {
2184
        if (metadata != null) {
2185
            metadata.clear();
2186
        }
2187
    }
2188

    
2189
    public String getName() {
2190
        return this.provider.getName();
2191
    }
2192

    
2193
    public String getFullName() {
2194
        try {
2195
            return this.provider.getFullName();
2196
        } catch(Throwable th) {
2197
            return null;
2198
        }
2199
    }
2200

    
2201
    public String getProviderName() {
2202
        return this.provider.getProviderName();
2203
    }
2204

    
2205
    public boolean isKnownEnvelope() {
2206
        return this.provider.isKnownEnvelope();
2207
    }
2208

    
2209
    public boolean hasRetrievedFeaturesLimit() {
2210
        return this.provider.hasRetrievedFeaturesLimit();
2211
    }
2212

    
2213
    public int getRetrievedFeaturesLimit() {
2214
        return this.provider.getRetrievedFeaturesLimit();
2215
    }
2216

    
2217
    public Interval getInterval() {
2218
        return this.provider.getInterval();
2219
    }
2220

    
2221
    public Collection getTimes() {
2222
        return this.provider.getTimes();
2223
    }
2224

    
2225
    public Collection getTimes(Interval interval) {
2226
        return this.provider.getTimes(interval);
2227
    }
2228

    
2229
    /* (non-Javadoc)
2230
     * @see java.lang.Object#clone()
2231
     */
2232
    public Object clone() throws CloneNotSupportedException {
2233

    
2234
        DataStoreParameters dsp = getParameters();
2235

    
2236
        DefaultFeatureStore cloned_store = null;
2237

    
2238
        try {
2239
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
2240
                openStore(this.getProviderName(), dsp);
2241
            if (transforms != null) {
2242
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
2243
                cloned_store.transforms.setStoreForClone(cloned_store);
2244
            }
2245
        } catch (Exception e) {
2246
            throw new CloneException(e);
2247
        }
2248
        return cloned_store;
2249

    
2250
    }
2251

    
2252
    public Feature getFeature(DynObject dynobject) {
2253
        if (dynobject instanceof DynObjectFeatureFacade){
2254
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
2255
            return f;
2256
        }
2257
        return null;
2258
    }
2259

    
2260
    public Iterator iterator() {
2261
        try {
2262
            return this.getFeatureSet().fastIterator();
2263
        } catch (DataException ex) {
2264
            throw new RuntimeException(ex);
2265
        }
2266
    }
2267

    
2268
    @Override
2269
    public ExpressionEvaluator createExpression() {
2270
        if( this.provider instanceof FeatureStoreProvider_v2 ) {
2271
            return ((FeatureStoreProvider_v2)this.provider).createExpression();
2272
        }
2273
        return new SQLBuilderBase();
2274
    }
2275
 
2276

    
2277
    public FeatureSet features() throws DataException {
2278
        // This is to avoid jython to create a property with this name
2279
        // to access method getFeatures.
2280
        return this.getFeatureSet();
2281
    }
2282
    
2283
}