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

History | View | Annotate | Download (113 KB)

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

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

    
27
import java.util.ArrayList;
28
import java.util.Collection;
29
import java.util.Collections;
30
import java.util.HashMap;
31
import java.util.HashSet;
32
import java.util.Iterator;
33
import java.util.List;
34
import java.util.Map;
35
import java.util.Map.Entry;
36
import java.util.Set;
37
import javax.json.JsonObject;
38
import org.apache.commons.io.FilenameUtils;
39
import org.apache.commons.io.IOUtils;
40
import org.apache.commons.lang3.StringUtils;
41
import org.apache.commons.lang3.mutable.MutableObject;
42
import org.cresques.cts.IProjection;
43
import org.gvsig.expressionevaluator.Expression;
44
import org.gvsig.expressionevaluator.ExpressionBuilder;
45
import org.gvsig.expressionevaluator.ExpressionUtils;
46
import org.gvsig.expressionevaluator.GeometryExpressionUtils;
47
import org.gvsig.fmap.dal.BaseStoresRepository;
48
import org.gvsig.fmap.dal.DALLocator;
49
import org.gvsig.fmap.dal.DataManager;
50
import org.gvsig.fmap.dal.DataQuery;
51
import org.gvsig.fmap.dal.DataServerExplorer;
52
import org.gvsig.fmap.dal.DataSet;
53
import org.gvsig.fmap.dal.DataStore;
54
import org.gvsig.fmap.dal.DataStoreNotification;
55
import org.gvsig.fmap.dal.DataStoreParameters;
56
import org.gvsig.fmap.dal.DataStoreProviderFactory;
57
import org.gvsig.fmap.dal.StoresRepository;
58
import org.gvsig.fmap.dal.exception.CloneException;
59
import org.gvsig.fmap.dal.exception.CloseException;
60
import org.gvsig.fmap.dal.exception.CreateException;
61
import org.gvsig.fmap.dal.exception.DataException;
62
import org.gvsig.fmap.dal.exception.InitializeException;
63
import org.gvsig.fmap.dal.exception.OpenException;
64
import org.gvsig.fmap.dal.exception.ReadException;
65
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
66
import org.gvsig.fmap.dal.exception.WriteException;
67
import org.gvsig.fmap.dal.feature.EditableFeature;
68
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
69
import org.gvsig.fmap.dal.feature.EditableFeatureType;
70
import org.gvsig.fmap.dal.feature.Feature;
71
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
72
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
73
import org.gvsig.fmap.dal.feature.FeatureCache;
74
import org.gvsig.fmap.dal.feature.FeatureIndex;
75
import org.gvsig.fmap.dal.feature.FeatureIndexes;
76
import org.gvsig.fmap.dal.feature.FeatureLocks;
77
import org.gvsig.fmap.dal.feature.FeatureQuery;
78
import org.gvsig.fmap.dal.feature.FeatureReference;
79
import org.gvsig.fmap.dal.feature.FeatureReferenceSelection;
80
import org.gvsig.fmap.dal.feature.FeatureRules;
81
import org.gvsig.fmap.dal.feature.FeatureSelection;
82
import org.gvsig.fmap.dal.feature.FeatureSet;
83
import org.gvsig.fmap.dal.feature.FeatureStore;
84
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
85
import org.gvsig.fmap.dal.feature.FeatureStoreProviderFactory;
86
import org.gvsig.fmap.dal.feature.FeatureStoreTimeSupport;
87
import org.gvsig.fmap.dal.feature.FeatureStoreTransform;
88
import org.gvsig.fmap.dal.feature.FeatureStoreTransforms;
89
import org.gvsig.fmap.dal.feature.FeatureType;
90
import org.gvsig.fmap.dal.feature.FeatureType.FeatureTypeChanged;
91
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
92
import org.gvsig.fmap.dal.feature.exception.AlreadyEditingException;
93
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
94
import org.gvsig.fmap.dal.feature.exception.CreateFeatureException;
95
import org.gvsig.fmap.dal.feature.exception.DataExportException;
96
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
97
import org.gvsig.fmap.dal.feature.exception.FinishEditingException;
98
import org.gvsig.fmap.dal.feature.exception.GetFeatureTypeException;
99
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureException;
100
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureTypeException;
101
import org.gvsig.fmap.dal.feature.exception.NeedEditingModeException;
102
import org.gvsig.fmap.dal.feature.exception.NoNewFeatureInsertException;
103
import org.gvsig.fmap.dal.feature.exception.NullFeatureTypeException;
104
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
105
import org.gvsig.fmap.dal.feature.exception.PersistenceCantFindFeatureTypeException;
106
import org.gvsig.fmap.dal.feature.exception.PersistenceStoreAlreadyLoadedException;
107
import org.gvsig.fmap.dal.feature.exception.SelectionNotAllowedException;
108
import org.gvsig.fmap.dal.feature.exception.StoreCancelEditingException;
109
import org.gvsig.fmap.dal.feature.exception.StoreDeleteEditableFeatureException;
110
import org.gvsig.fmap.dal.feature.exception.StoreDeleteFeatureException;
111
import org.gvsig.fmap.dal.feature.exception.StoreEditException;
112
import org.gvsig.fmap.dal.feature.exception.StoreInsertFeatureException;
113
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureException;
114
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureTypeException;
115
import org.gvsig.fmap.dal.feature.exception.ValidateFeaturesException;
116
import org.gvsig.fmap.dal.feature.exception.WriteNotAllowedException;
117
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
118
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureManager;
119
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureTypeManager;
120
import org.gvsig.fmap.dal.feature.impl.editing.memory.SpatialManager;
121
import org.gvsig.fmap.dal.feature.impl.featureset.DefaultFeatureSet;
122
import org.gvsig.fmap.dal.feature.impl.undo.DefaultFeatureCommandsStack;
123
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
124
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
125
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
126
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
127
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
128
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
129
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
130
import org.gvsig.fmap.dal.feature.spi.cache.FeatureCacheProvider;
131
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProviderServices;
132
import org.gvsig.fmap.dal.impl.DefaultDataManager;
133
import org.gvsig.fmap.dal.resource.Resource;
134
import org.gvsig.fmap.dal.spi.AbstractDataStore;
135
import org.gvsig.fmap.dal.spi.DataStoreInitializer2;
136
import org.gvsig.fmap.dal.spi.DataStoreProvider;
137
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
138
import org.gvsig.fmap.geom.Geometry;
139
import org.gvsig.fmap.geom.SpatialIndex;
140
import org.gvsig.fmap.geom.primitive.Envelope;
141
import org.gvsig.metadata.MetadataLocator;
142
import org.gvsig.metadata.MetadataManager;
143
import org.gvsig.metadata.exceptions.MetadataException;
144
import org.gvsig.timesupport.Interval;
145
import org.gvsig.tools.ToolsLocator;
146
import org.gvsig.tools.dispose.DisposableIterator;
147
import org.gvsig.tools.dispose.DisposeUtils;
148
import org.gvsig.tools.dynobject.DelegatedDynObject;
149
import org.gvsig.tools.dynobject.DynClass;
150
import org.gvsig.tools.dynobject.DynObject;
151
import org.gvsig.tools.dynobject.DynObjectManager;
152
import org.gvsig.tools.dynobject.DynObject_v2;
153
import org.gvsig.tools.dynobject.DynStruct;
154
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
155
import org.gvsig.tools.dynobject.exception.DynMethodException;
156
import org.gvsig.tools.exception.BaseException;
157
import org.gvsig.tools.exception.NotYetImplemented;
158
import org.gvsig.tools.identitymanagement.SimpleIdentityManager;
159
import org.gvsig.tools.observer.Observable;
160
import org.gvsig.tools.observer.Observer;
161
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
162
import org.gvsig.tools.persistence.PersistenceManager;
163
import org.gvsig.tools.persistence.Persistent;
164
import org.gvsig.tools.persistence.PersistentState;
165
import org.gvsig.tools.persistence.exception.PersistenceException;
166
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
167
import org.gvsig.tools.undo.RedoException;
168
import org.gvsig.tools.undo.UndoException;
169
import org.gvsig.tools.undo.command.Command;
170
import org.gvsig.tools.util.HasAFile;
171
import org.gvsig.tools.util.UnmodifiableBasicMap;
172
import org.gvsig.tools.visitor.VisitCanceledException;
173
import org.gvsig.tools.visitor.Visitor;
174

    
175
@SuppressWarnings("UseSpecificCatch")
176
public class DefaultFeatureStore extends AbstractDataStore implements
177
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
178

    
179
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
180

    
181
    private DataStoreParameters parameters = null;
182
    private FeatureSelection selection;
183
    private FeatureLocks locks;
184

    
185
    private DelegateWeakReferencingObservable delegateObservable =
186
        new DelegateWeakReferencingObservable(this);
187

    
188
    private FeatureCommandsStack commands;
189
    
190
    /*
191
    TODO: Sustituir estos tres manager por un EditingManager
192
    */
193
    private FeatureTypeManager featureTypeManager;
194
    private FeatureManager featureManager;
195
    private SpatialManager spatialManager;
196

    
197
    private FeatureType defaultFeatureType = null;
198
    private List<FeatureType> featureTypes = new ArrayList<>();
199

    
200
    private int mode = MODE_QUERY;
201
    private long versionOfUpdate = 0;
202
    private boolean hasStrongChanges = true;
203
    private boolean hasInserts = true;
204

    
205
    private DefaultDataManager dataManager = null;
206

    
207
    private FeatureStoreProvider provider = null;
208

    
209
    private DefaultFeatureIndexes indexes;
210

    
211
    private DefaultFeatureStoreTransforms transforms;
212

    
213
    DelegatedDynObject metadata;
214

    
215
    private Set metadataChildren;
216

    
217
    private Long featureCount = null;
218

    
219
    private long temporalOid = 0;
220

    
221
    private FeatureCacheProvider cache;
222

    
223
    StateInformation state;
224

    
225
    FeatureStoreTimeSupport timeSupport;
226

    
227

    
228
    private class StateInformation extends HashMap<Object, Object> {
229

    
230
        private static final long serialVersionUID = 4109026189635185666L;
231

    
232
        private boolean broken;
233
        private Throwable breakingsCause;
234

    
235
        @SuppressWarnings("OverridableMethodCallInConstructor")
236
        public StateInformation() {
237
            this.clear();
238
        }
239

    
240
        @Override
241
        public void clear() {
242
            this.broken = false;
243
            this.breakingsCause = null;
244
            super.clear();
245
        }
246

    
247
        public boolean isBroken() {
248
            return this.broken;
249
        }
250

    
251
        public void broken() {
252
            this.broken = true;
253
        }
254

    
255
        public Throwable getBreakingsCause() {
256
            return this.breakingsCause;
257
        }
258

    
259
        public void setBreakingsCause(Throwable cause) {
260
            if( this.breakingsCause==null ) {
261
                this.breakingsCause = cause;
262
            }
263
            this.broken = true;
264
        }
265
    }
266

    
267

    
268

    
269
    /*
270
     * TODO:
271
     *
272
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
273
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
274
     * featureType al que se le han cambiado las reglas de validacion cuando
275
     * hasStrongChanges=false.
276
     */
277

    
278
    public DefaultFeatureStore() {
279
        this.state = new StateInformation();
280
    }
281
    
282
    @Override
283
    protected DataManager getDataManager() {
284
        return this.dataManager;
285
    }
286

    
287
    @Override
288
    public void intialize(DataManager dataManager,
289
        DataStoreParameters parameters) throws InitializeException {
290

    
291
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
292

    
293
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
294
            FeatureStore.METADATA_DEFINITION_NAME,
295
            MetadataManager.METADATA_NAMESPACE
296
        );
297

    
298
        this.dataManager = (DefaultDataManager) dataManager;
299

    
300
        this.parameters = parameters;
301
        this.transforms = new DefaultFeatureStoreTransforms(this);
302
        try {
303
            indexes = new DefaultFeatureIndexes(this);
304
        } catch (DataException e) {
305
            throw new InitializeException(e);
306
        }
307

    
308
    }
309

    
310
    @Override
311
    public void setProvider(org.gvsig.fmap.dal.DataStoreProvider provider) {
312
        this.provider = (FeatureStoreProvider) provider;
313
        this.delegate((DynObject) provider);
314
        this.metadataChildren = new HashSet();
315
        this.metadataChildren.add(provider);
316
        loadDALFile();
317
        
318
        // Habria que crear un metodo en el proveedor para que de prioidad
319
        // a los parametros frente a lo que se a leido en el fichero dal
320
        // DataStoreProvider arreglalo segun los parametros del usuario
321
        // fixFeatureTypeFromParameters
322
        try {
323
            if( defaultFeatureType!=null ) {
324
                FeatureAttributeDescriptor attrGeom = defaultFeatureType.getDefaultGeometryAttribute();
325
                if (attrGeom!=null) {
326
                    DefaultFeatureAttributeDescriptor gattr = (DefaultFeatureAttributeDescriptor) attrGeom;
327
                    IProjection srs = (IProjection) this.getDynValue(METADATA_CRS);
328
                    if( srs!=null && srs!=gattr.getSRS() ) {
329
                        gattr.setSRSForced(srs);
330
                    }
331
                }
332
            }
333
        } catch(Throwable th) {
334
            LOGGER.warn("Can't patch DAL file",th);
335
        }
336
    }
337

    
338
    @Override
339
    public DataStoreParameters getParameters() {
340
        if( this.parameters==null ) {
341
            LOGGER.warn("Store parametes are null");
342
        }
343
        return parameters;
344
    }
345

    
346
    public int getMode() {
347
        return this.mode;
348
    }
349

    
350
    @Override
351
    public DataManager getManager() {
352
        return this.dataManager;
353
    }
354

    
355
    @Override
356
    public UnmodifiableBasicMap<String,DataStore> getChildren() {
357
        UnmodifiableBasicMap<String, DataStore> children = this.provider.getChildren();
358
        if( children == null ) {
359
            return UnmodifiableBasicMap.EMPTY_UNMODIFIABLEBASICMAP;
360
        }
361
        return children;
362
    }
363

    
364
    @Override
365
    public FeatureStoreProvider getProvider() {
366
        return this.provider;
367
    }
368

    
369
    public FeatureManager getFeatureManager() {
370
        return this.featureManager;
371
    }
372

    
373
    @Override
374
    public void setFeatureTypes(List types, FeatureType defaultType) {
375
        this.featureTypes = types;
376
        this.defaultFeatureType = defaultType;
377
    }
378

    
379
    public void open() throws OpenException {
380
        if (this.mode != MODE_QUERY) {
381
            // TODO: Se puede hacer un open estando en edicion ?
382
            try {
383
                throw new IllegalStateException();
384
            } catch(Exception ex) {
385
                LOGGER.warn("Opening a store in editing/append mode ("+this.getFullName()+").",ex);
386
            }
387
        }
388
        if( this.notifyChange(DataStoreNotification.BEFORE_OPEN).isCanceled() ) {
389
          return;
390
        }
391
        this.provider.open();
392
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
393
    }
394

    
395
    @Override
396
    public void refresh() throws OpenException, InitializeException {
397
        if (this.mode != MODE_QUERY) {
398
            throw new IllegalStateException();
399
        }
400
        if( this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH).isCanceled() ) {
401
          return;
402
        }
403
        if( state.isBroken() ) {
404
            this.load(state);
405
        } else {
406
            this.featureCount = null;
407
            this.provider.refresh();
408
        }
409
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
410
    }
411

    
412
    public void close() throws CloseException {
413
        if (this.mode != MODE_QUERY) {
414
            // TODO: Se puede hacer un close estando en edicion ?
415
            try {
416
                throw new IllegalStateException();
417
            } catch(Exception ex) {
418
                LOGGER.warn("Clossing a store in editing/append mode ("+this.getFullName()+").",ex);
419
            }
420
        }
421
        if( this.notifyChange(DataStoreNotification.BEFORE_CLOSE).isCanceled() ) {
422
          return;
423
        }
424
        this.featureCount = null;
425
        this.provider.close();
426
        this.notifyChange(DataStoreNotification.AFTER_CLOSE);
427
    }
428

    
429
    @Override
430
    protected void doDispose() throws BaseException {
431
        if (this.mode != MODE_QUERY) {
432
            // TODO: Se puede hacer un dispose estando en edicion ?
433
            try {
434
                throw new IllegalStateException();
435
            } catch(Exception ex) {
436
                LOGGER.warn("Dispossing a store in editing/append mode ("+this.getFullName()+").",ex);
437
            }
438
        }
439
        if( this.notifyChange(DataStoreNotification.BEFORE_DISPOSE).isCanceled() ) {
440
          return;
441
        }
442
        this.disposeIndexes();
443
        if( this.provider!=null ) {
444
            this.provider.dispose();
445
        }
446
        if (this.selection != null) {
447
            this.selection.dispose();
448
            this.selection = null;
449
        }
450
        this.commands = null;
451
        this.featureCount = null;
452
        if (this.locks != null) {
453
            // this.locks.dispose();
454
            this.locks = null;
455
        }
456

    
457
        if (this.featureTypeManager != null) {
458
            this.featureTypeManager.dispose();
459
            this.featureTypeManager = null;
460
        }
461

    
462
        this.featureManager = null;
463
        this.spatialManager = null;
464

    
465
        this.parameters = null;
466
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
467
        if (delegateObservable != null) {
468
            this.delegateObservable.deleteObservers();
469
            this.delegateObservable = null;
470
        }
471
    }
472

    
473
    @Override
474
    public boolean allowWrite() {
475
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
476
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
477
            return false;
478
        }
479
        return this.provider.allowWrite();
480
    }
481

    
482
    @Override
483
    public boolean canWriteGeometry(int geometryType) throws DataException {
484
        return this.provider.canWriteGeometry(geometryType, 0);
485
    }
486

    
487
    @Override
488
    public DataServerExplorer getExplorer() throws ReadException,
489
        ValidateDataParametersException {
490
        if( this.state.isBroken() ) {
491
            try {
492
                return this.provider.getExplorer();
493
            } catch(Throwable th) {
494
                return null;
495
            }
496
        } else {
497
            return this.provider.getExplorer();
498
        }
499
    }
500

    
501
    /*
502
     * public Metadata getMetadata() throws MetadataNotFoundException {
503
     * // TODO:
504
     * // Si el provider devuelbe null habria que ver de construir aqui
505
     * // los metadatos basicos, como el Envelope y el SRS.
506
     *
507
     * // TODO: Estando en edicion el Envelope deberia de
508
     * // actualizarse usando el spatialManager
509
     * return this.provider.getMetadata();
510
     * }
511
     */
512

    
513
    @Override
514
    public Envelope getEnvelope() throws DataException {
515
        if (this.mode == MODE_FULLEDIT) {
516
                // Just in case another thread tries to write in the store
517
                synchronized (this) {
518
                        return this.spatialManager.getEnvelope();
519
                        }
520
        }
521
        if (hasDynValue(DataStore.METADATA_ENVELOPE)){
522
            return (Envelope)getDynValue(DataStore.METADATA_ENVELOPE);
523
        }
524
        Envelope envelope = this.provider.getEnvelope();
525
        if( envelope!=null ) {
526
            return envelope;
527
        }
528
        FeatureAttributeDescriptor attrdesc = this.getDefaultFeatureType().getDefaultGeometryAttribute();
529
        if( attrdesc == null || !attrdesc.isComputed() ) {
530
            return null;
531
        }
532
        final int index = attrdesc.getIndex();
533
        final MutableObject<Envelope> envelopeValue = new MutableObject<>();
534
        try {
535
            this.accept(new Visitor() {
536
                @Override
537
                public void visit(Object obj) throws VisitCanceledException, BaseException {
538
                    Feature f = (Feature) obj;
539
                    Geometry g =  (Geometry) f.get(index);
540
                    if( g == null ) {
541
                        return;
542
                    }
543
                    if( envelopeValue.getValue()==null ) {
544
                        envelopeValue.setValue(g.getEnvelope());
545
                    } else {
546
                        envelopeValue.getValue().add(g);
547
                    }
548
                }
549
            });
550
        } catch (Throwable th) {
551
            LOGGER.warn("Can't calculate envelope", th);
552
            return null;
553
        }
554
        return envelopeValue.getValue();
555
    }
556

    
557
    /**
558
     * @throws org.gvsig.fmap.dal.exception.DataException
559
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
560
     */
561
    @Override
562
    public IProjection getSRSDefaultGeometry() throws DataException {
563
        return this.getDefaultFeatureType().getDefaultSRS();
564
    }
565

    
566
    @Override
567
    public FeatureSelection createDefaultFeatureSelection()
568
        throws DataException {
569
        return new DefaultFeatureSelection(this);
570
    }
571

    
572
    @Override
573
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
574
        throws DataException {
575
        if (type.hasOID()) {
576
            return new DefaultFeatureProvider(type,
577
                this.provider.createNewOID());
578
        }
579
        return new DefaultFeatureProvider(type);
580
    }
581

    
582
    @Override
583
    public void saveToState(PersistentState state) throws PersistenceException {
584
        /*if (this.mode != FeatureStore.MODE_QUERY) {
585
            throw new PersistenceException(new IllegalStateException(
586
                this.getName()));
587
        }*/
588
        state.set("dataStoreName", this.getName());
589
        state.set("parameters", this.parameters);
590
        state.set("selection", this.selection);
591
        state.set("transforms", this.transforms);
592
        // TODO locks persistence
593
        // state.set("locks", this.locks);
594
        // TODO indexes persistence
595
        // state.set("indexes", this.indexes);
596
        Map evaluatedAttr = new HashMap(1);
597
        Iterator iterType = featureTypes.iterator();
598
        Iterator iterAttr;
599
        FeatureType type;
600
        DefaultFeatureAttributeDescriptor attr;
601
        List attrs;
602
        while (iterType.hasNext()) {
603
            type = (FeatureType) iterType.next();
604
            attrs = new ArrayList();
605
            iterAttr = type.iterator();
606
            while (iterAttr.hasNext()) {
607
                attr = (DefaultFeatureAttributeDescriptor) iterAttr.next();
608
                if ((attr.getEvaluator() != null)
609
                    && (attr.getEvaluator() instanceof Persistent)) {
610
                    attrs.add(attr);
611
                }
612
            }
613
            if (!attrs.isEmpty()) {
614
                evaluatedAttr.put(type.getId(), attrs);
615
            }
616

    
617
        }
618

    
619
        if (evaluatedAttr.isEmpty()) {
620
            evaluatedAttr = null;
621
        }
622

    
623
        state.set("evaluatedAttributes", evaluatedAttr);
624
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
625

    
626
    }
627

    
628
    @Override
629
    public void loadFromState(final PersistentState persistentState)
630
        throws PersistenceException {
631
        if (this.provider != null) {
632
            throw new PersistenceStoreAlreadyLoadedException(this.getName());
633
        }
634
        if (this.getManager() == null) {
635
            this.dataManager = (DefaultDataManager) DALLocator.getDataManager();
636
        }
637
        state.clear();
638
        try {
639
            state.put("parameters", persistentState.get("parameters"));
640
        } catch(Throwable th) {
641
            state.setBreakingsCause(th);
642
        }
643
        try {
644
            state.put("selection", persistentState.get("selection"));
645
        } catch(Throwable th) {
646
            state.setBreakingsCause(th);
647
        }
648
        try {
649
            state.put("transforms",  persistentState.get("transforms"));
650
        } catch(Throwable th) {
651
            state.setBreakingsCause(th);
652
        }
653
        try {
654
            state.put("evaluatedAttributes",  persistentState.get("evaluatedAttributes"));
655
        } catch(Throwable th) {
656
            state.setBreakingsCause(th);
657
        }
658
        try {
659
            state.put("defaultFeatureTypeId", persistentState.getString("defaultFeatureTypeId"));
660
        } catch(Throwable th) {
661
            state.setBreakingsCause(th);
662
        }
663
        load(state);
664
    }
665

    
666
    private void load(StateInformation state) {
667
        this.featureTypes = new ArrayList();
668
        this.defaultFeatureType = null;
669
        this.featureCount = null;
670

    
671
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
672
        try {
673
            intialize(dataManager, params);
674
        } catch(Throwable th) {
675
            state.setBreakingsCause(th);
676
        }
677

    
678
        try {
679
            DataStoreProvider prov = dataManager.createProvider(
680
                getStoreProviderServices(),
681
                params
682
            );
683
            setProvider(prov);
684
        } catch(Throwable th) {
685
            LOGGER.warn("Can't load store from state.", th);
686
            state.setBreakingsCause(th);
687
        }
688
        try {
689
            selection = (FeatureSelection) state.get("selection");
690
        } catch(Throwable th) {
691
            state.setBreakingsCause(th);
692
        }
693

    
694
        try {
695
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
696
            this.transforms.setFeatureStore(this);
697
            for( FeatureStoreTransform transform : this.transforms ) {
698
                try {
699
                    transform.setUp();
700
                } catch(Throwable th) {
701
                    state.setBreakingsCause(th);
702
                }
703
            }
704
        } catch(Throwable th) {
705
            state.setBreakingsCause(th);
706
        }
707

    
708
        try {
709
            Map evaluatedAttributes = (Map) state.get("evaluatedAttributes");
710
            if ((evaluatedAttributes != null) && !evaluatedAttributes.isEmpty()) {
711
                    Iterator iterEntries = evaluatedAttributes.entrySet().iterator();
712
                    while (iterEntries.hasNext()) {
713
                            Entry entry = (Entry) iterEntries.next();
714
                            List attrs = (List) entry.getValue();
715
                            if (attrs.isEmpty()) {
716
                                    continue;
717
                            }
718
                            int fTypePos = -1;
719
                            DefaultFeatureType type = null;
720
                            for (int i = 0; i < featureTypes.size(); i++) {
721
                                    type = (DefaultFeatureType) featureTypes.get(i);
722
                                    if (type.getId().equals(entry.getKey())) {
723
                                            fTypePos = i;
724
                                            break;
725
                                    }
726
                            }
727
                            if (type == null) {
728
                                    throw new PersistenceCantFindFeatureTypeException(
729
                                            getName(), (String) entry.getKey());
730
                            }
731
                            DefaultEditableFeatureType eType = (DefaultEditableFeatureType) type.getEditable();
732
                            Iterator<FeatureAttributeDescriptor> iterAttr = attrs.iterator();
733
                            while (iterAttr.hasNext()) {
734
                                    FeatureAttributeDescriptor attr = iterAttr.next();
735
                                    eType.addLike(attr);
736
                            }
737
                            featureTypes.set(fTypePos, eType.getNotEditableCopy());
738

    
739
                    }
740

    
741
            }
742
        } catch(Throwable th) {
743
            state.setBreakingsCause(th);
744
        }
745

    
746

    
747
        try {
748
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
749
            FeatureType ftype;
750

    
751
            if (defaultFeatureType == null ||
752
                    defaultFeatureType.getId() == null ||
753
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
754

    
755
                    ftype = getFeatureType(defaultFeatureTypeId);
756
                    if (ftype == null) {
757
                            /*
758
                             * Un error en el m?todo de PostgreSQL getName(), hace que
759
                             * el nombre del featureType sea valor retornado por el getProviderName()
760
                             * De momento se pone este parche para apa?arlo y poder mantener compatibilidad
761
                             * con proyectos antiguos (2.1 y 2.2)
762
                             */
763
                            ftype = getFeatureType(getName());
764
                            if(ftype == null ) {
765
                                    throw new RuntimeException("Can't locate feature type");
766
                            }
767
                    }
768
                    defaultFeatureType = ftype;
769
            }
770
        } catch(Throwable th) {
771
            state.setBreakingsCause(th);
772
        }
773

    
774
        LOGGER.info("load() broken:{}, {}, {}.",
775
                new Object[] { state.isBroken(), this.getProviderName(), params }
776
        );
777
    }
778

    
779
    public DataStoreProviderServices getStoreProviderServices() {
780
        return this;
781
    }
782

    
783
    public static void registerPersistenceDefinition() {
784
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
785
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
786
            DynStruct definition =
787
                manager.addDefinition(DefaultFeatureStore.class,
788
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
789
                        + " Persistent definition", null, null);
790
            definition.addDynFieldString("dataStoreName").setMandatory(true)
791
                .setPersistent(true);
792

    
793
            definition.addDynFieldObject("parameters")
794
                .setClassOfValue(DynObject.class).setMandatory(true)
795
                .setPersistent(true);
796

    
797
            definition.addDynFieldObject("selection")
798
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
799
                .setPersistent(true);
800

    
801
            definition.addDynFieldObject("transforms")
802
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
803
                .setMandatory(true).setPersistent(true);
804

    
805
            definition.addDynFieldMap("evaluatedAttributes")
806
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
807
                .setMandatory(false).setPersistent(true);
808

    
809
            definition.addDynFieldString("defaultFeatureTypeId")
810
                .setMandatory(true).setPersistent(true);
811
        }
812
    }
813

    
814
    public static void registerMetadataDefinition() throws MetadataException {
815
        MetadataManager manager = MetadataLocator.getMetadataManager();
816
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
817
            DynStruct metadataDefinition =
818
                manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
819
            metadataDefinition.extend(manager
820
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
821
        }
822
    }
823

    
824
    //
825
    // ====================================================================
826
    // Gestion de la seleccion
827
    //
828

    
829
    @Override
830
    public void setSelection(DataSet selection) throws DataException {
831
        this.setSelection((FeatureSet) selection);
832
    }
833

    
834
    @Override
835
    public DataSet createSelection() throws DataException {
836
        return createFeatureSelection();
837
    }
838

    
839
    @Override
840
    public DataSet getSelection() throws DataException {
841
        return this.getFeatureSelection();
842
    }
843

    
844
    @Override
845
    public void setSelection(FeatureSet selection) throws DataException {
846
        setSelection(selection, true);
847
    }
848

    
849
    public void setSelection(FeatureSet selection, boolean undoable)
850
        throws DataException {
851
        if (selection == null) {
852
            if (undoable) {
853
                throw new SelectionNotAllowedException(getName());
854
            }
855

    
856
        } else {
857
            if (selection.equals(this.selection)) {
858
                return;
859
            }
860
            if (!selection.isFromStore(this)) {
861
                throw new SelectionNotAllowedException(getName());
862
            }
863
        }
864

    
865
        if (this.selection != null) {
866
            this.selection.deleteObserver(this);
867
        }
868
        if (selection == null) {
869
            if (this.selection != null) {
870
                this.selection.dispose();
871
            }
872
            this.selection = null;
873
            return;
874
        }
875
        if (selection instanceof FeatureSelection) {
876
            if (undoable && isEditing()) {
877
                commands.selectionSet(this, this.selection,
878
                    (FeatureSelection) selection);
879
            }
880
            if (this.selection != null) {
881
                this.selection.dispose();
882
            }
883
            this.selection = (FeatureSelection) selection;
884
        } else {
885
            if (undoable && isEditing()) {
886
                commands.startComplex("_selectionSet");
887
            }
888
            if (selection instanceof DefaultFeatureSelection) {
889
                DefaultFeatureSelection defSelection =
890
                    (DefaultFeatureSelection) selection;
891
                defSelection.deselectAll(undoable);
892
                defSelection.select(selection, undoable);
893
            } else {
894
                this.selection.deselectAll();
895
                this.selection.select(selection);
896
            }
897
            if (undoable && isEditing()) {
898
                commands.endComplex();
899
            }
900
        }
901
        this.selection.addObserver(this);
902

    
903
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
904
    }
905

    
906
    @Override
907
    public FeatureSelection createFeatureSelection() throws DataException {
908
        return this.provider.createFeatureSelection();
909
    }
910

    
911
    @Override
912
    public FeatureSelection getFeatureSelection() throws DataException {
913
        if (selection == null) {
914
            this.selection = createFeatureSelection();
915
            this.selection.addObserver(this);
916
        }
917
        return selection;
918
    }
919

    
920
    //
921
    // ====================================================================
922
    // Gestion de notificaciones
923
    //
924

    
925
    @Override
926
    public FeatureStoreNotification notifyChange(FeatureStoreNotification storeNotification) {
927
        if (delegateObservable != null) {
928
          try {
929
              delegateObservable.notifyObservers(storeNotification);
930
          } catch (Throwable ex) {
931
              LOGGER.warn("Problems notifying changes in the store '"+this.getName()+" ("+storeNotification.getType()+").",ex);
932
          }
933
        }
934
        return storeNotification;
935
    }
936

    
937
    @Override
938
    public FeatureStoreNotification notifyChange(String notification) {
939
      return notifyChange(new DefaultFeatureStoreNotification(this, notification));
940
    }
941
    
942
    public FeatureStoreNotification notifyChange(String notification,
943
      Iterator<FeatureReference> deleteds, 
944
      Iterator<Feature> inserteds, 
945
      Iterator<Feature> updateds, 
946
      Iterator<FeatureTypeChanged> featureTypesChanged, 
947
      boolean isSelectionCompromised) {
948
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
949
            deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised));
950
    }
951

    
952
    @Override
953
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
954
        Feature f = null;
955
        if( data !=null ) {
956
          try {
957
              f = createFeature(data);
958
          } catch (Throwable ex) {
959
              LOGGER.warn("Problems creating a feature to notifying changes in the store '"+this.getName()+" ("+notification+").",ex);
960
          }
961
        }
962
        return notifyChange(notification, f);
963
    }
964

    
965
    public FeatureStoreNotification notifyChange(String notification, Feature feature) {
966
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
967
            feature));
968
    }
969

    
970
    public FeatureStoreNotification notifyChange(String notification, Command command) {
971
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
972
            command));
973
    }
974

    
975
    public FeatureStoreNotification notifyChange(String notification, EditableFeatureType type) {
976
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
977
            type));
978
    }
979

    
980
    @Override
981
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
982
        return notifyChange(new DefaultFeatureStoreNotification(this,
983
            DataStoreNotification.RESOURCE_CHANGED));
984
    }
985

    
986
    //
987
    // ====================================================================
988
    // Gestion de bloqueos
989
    //
990

    
991
    @Override
992
    public boolean isLocksSupported() {
993
        return this.provider.isLocksSupported();
994
    }
995

    
996
    @Override
997
    public FeatureLocks getLocks() throws DataException {
998
        if (!this.provider.isLocksSupported()) {
999
            LOGGER.warn("Locks not supported");
1000
            return null;
1001
        }
1002
        if (locks == null) {
1003
            this.locks = this.provider.createFeatureLocks();
1004
        }
1005
        return locks;
1006
    }
1007

    
1008
    //
1009
    // ====================================================================
1010
    // Interface Observable
1011
    //
1012

    
1013
    @Override
1014
    public void disableNotifications() {
1015
        this.delegateObservable.disableNotifications();
1016

    
1017
    }
1018

    
1019
    @Override
1020
    public void enableNotifications() {
1021
        this.delegateObservable.enableNotifications();
1022
    }
1023

    
1024
    @Override
1025
    public void beginComplexNotification() {
1026
        this.delegateObservable.beginComplexNotification();
1027

    
1028
    }
1029

    
1030
    @Override
1031
    public void endComplexNotification() {
1032
        this.delegateObservable.endComplexNotification();
1033

    
1034
    }
1035

    
1036
    @Override
1037
    public void addObserver(Observer observer) {
1038
        if (delegateObservable != null) {
1039
            this.delegateObservable.addObserver(observer);
1040
        }
1041
    }
1042

    
1043
    @Override
1044
    public void deleteObserver(Observer observer) {
1045
        if (delegateObservable != null) {
1046
            this.delegateObservable.deleteObserver(observer);
1047
        }
1048
    }
1049

    
1050
    @Override
1051
    public void deleteObservers() {
1052
        this.delegateObservable.deleteObservers();
1053

    
1054
    }
1055

    
1056
    //
1057
    // ====================================================================
1058
    // Interface Observer
1059
    //
1060
    // Usado para observar:
1061
    // - su seleccion
1062
    // - sus bloqueos
1063
    // - sus recursos
1064
    //
1065

    
1066
    @Override
1067
    public void update(Observable observable, Object notification) {
1068
        if (observable instanceof FeatureSet) {
1069
            if (observable == this.selection) {
1070
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1071
            } else if (observable == this.locks) {
1072
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1073
            }
1074

    
1075
        } else if (observable instanceof FeatureStoreProvider) {
1076
            if (observable == this.provider) {
1077

    
1078
            }
1079
        } else if (observable instanceof FeatureReferenceSelection) {
1080
            if(notification instanceof String){
1081
                    this.notifyChange((String)notification);
1082
            }
1083
        }
1084
    }
1085

    
1086
    //
1087
    // ====================================================================
1088
    // Edicion
1089
    //
1090

    
1091
    private void newVersionOfUpdate() {
1092
        this.versionOfUpdate++;
1093
    }
1094

    
1095
    private long currentVersionOfUpdate() {
1096
        return this.versionOfUpdate;
1097
    }
1098

    
1099
    private void checkInEditingMode() throws NeedEditingModeException {
1100
        if (mode != MODE_FULLEDIT) {
1101
            throw new NeedEditingModeException(this.getName());
1102
        }
1103
    }
1104

    
1105
    private void checkNotInAppendMode() throws IllegalStateException {
1106
        if (mode == MODE_APPEND) {
1107
                        throw new IllegalStateException("Error: store "
1108
                                        + this.getFullName() + " is in append mode");
1109
        }
1110
    }
1111

    
1112
    private void checkIsOwnFeature(Feature feature)
1113
        throws IllegalFeatureException {
1114
        if (((DefaultFeature) feature).getStore() != this) {
1115
            throw new IllegalFeatureException(this.getName());
1116
        }
1117
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1118
        // fixFeatureType((DefaultFeatureType) feature.getType());
1119
    }
1120

    
1121
    private void exitEditingMode() {
1122
        if (commands != null) {
1123
            commands.clear();
1124
            commands = null;
1125
        }
1126

    
1127
        if (featureTypeManager != null) {
1128
            featureTypeManager.dispose();
1129
            featureTypeManager = null;
1130

    
1131
        }
1132

    
1133
        // TODO implementar un dispose para estos dos
1134
        featureManager = null;
1135
        spatialManager = null;
1136

    
1137
        featureCount = null;
1138

    
1139
        mode = MODE_QUERY;
1140
        hasStrongChanges = true; // Lo deja a true por si las moscas
1141
        hasInserts = true;
1142
    }
1143

    
1144
    @Override
1145
    synchronized public void edit() throws DataException {
1146
        edit(MODE_FULLEDIT);
1147
    }
1148

    
1149
    @Override
1150
    synchronized public void edit(int mode) throws DataException {
1151
        LOGGER.debug("Starting editing in mode: {}", mode);
1152
        try {
1153
            if (this.mode != MODE_QUERY) {
1154
                throw new AlreadyEditingException(this.getName());
1155
            }
1156
            if (!this.provider.supportsAppendMode()) {
1157
                mode = MODE_FULLEDIT;
1158
            }
1159
            switch (mode) {
1160
            case MODE_QUERY:
1161
                throw new IllegalStateException(this.getName());
1162

    
1163
            case MODE_FULLEDIT:
1164
                if (!this.transforms.isEmpty()) {
1165
                    throw new IllegalStateException(this.getName());
1166
                }
1167
                if( notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING).isCanceled() ) {
1168
                  return;
1169
                }
1170
                invalidateIndexes();
1171
                featureManager = new FeatureManager();
1172
                featureTypeManager = new FeatureTypeManager(this);
1173
                spatialManager = new SpatialManager(this, provider.getEnvelope());
1174

    
1175
                commands = new DefaultFeatureCommandsStack(
1176
                        this, featureManager,
1177
                        spatialManager, featureTypeManager);
1178
                this.mode = MODE_FULLEDIT;
1179
                hasStrongChanges = false;
1180
                hasInserts = false;
1181
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1182
                break;
1183
            case MODE_APPEND:
1184
                if (!this.transforms.isEmpty()) {
1185
                    throw new IllegalStateException(this.getName());
1186
                }
1187
                if( notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING).isCanceled() ) {
1188
                  return;
1189
                }
1190
                invalidateIndexes();
1191
                this.provider.beginAppend();
1192
                this.mode = MODE_APPEND;
1193
                hasInserts = false;
1194
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1195
                break;
1196
            }
1197
        } catch (Exception e) {
1198
            throw new StoreEditException(e, this.getName());
1199
        }
1200
    }
1201

    
1202
    private void invalidateIndexes() {
1203
        setIndexesValidStatus(false);
1204
    }
1205

    
1206
    private void setIndexesValidStatus(boolean valid) {
1207
        FeatureIndexes theIndexes = getIndexes();
1208
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1209
            ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1210
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1211
            FeatureIndex index = (FeatureIndex) iterator.next();
1212
            if (index instanceof FeatureIndexProviderServices) {
1213
                FeatureIndexProviderServices indexServices =
1214
                    (FeatureIndexProviderServices) index;
1215
                indexServices.setValid(valid);
1216
            }
1217
        }
1218
    }
1219

    
1220
    private void updateIndexes() throws FeatureIndexException {
1221
        FeatureIndexes theIndexes = getIndexes();
1222
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1223
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1224
            FeatureIndex index = (FeatureIndex) iterator.next();
1225
            if (index instanceof FeatureIndexProviderServices) {
1226
                FeatureIndexProviderServices indexServices =
1227
                    (FeatureIndexProviderServices) index;
1228
                indexServices.fill(true, null);
1229
            }
1230
        }
1231
    }
1232

    
1233
    private void waitForIndexes() {
1234
        FeatureIndexes theIndexes = getIndexes();
1235
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1236
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1237
            FeatureIndex index = (FeatureIndex) iterator.next();
1238
            if (index instanceof FeatureIndexProviderServices) {
1239
                FeatureIndexProviderServices indexServices =
1240
                    (FeatureIndexProviderServices) index;
1241
                indexServices.waitForIndex();
1242
            }
1243
        }
1244
    }
1245

    
1246
    private void disposeIndexes() {
1247
        FeatureIndexes theIndexes = getIndexes();
1248
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1249
        if( theIndexes==null ) {
1250
            return;
1251
        }
1252
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1253
            FeatureIndex index = (FeatureIndex) iterator.next();
1254
            if (index instanceof FeatureIndexProviderServices) {
1255
                FeatureIndexProviderServices indexServices =
1256
                    (FeatureIndexProviderServices) index;
1257
                indexServices.dispose();
1258
            }
1259
        }
1260
    }
1261

    
1262
    @Override
1263
    public boolean isEditing() {
1264
        return mode == MODE_FULLEDIT;
1265
    }
1266

    
1267
    @Override
1268
    public boolean isAppending() {
1269
        return mode == MODE_APPEND;
1270
    }
1271

    
1272
    @Override
1273
    synchronized public void update(EditableFeatureType type)
1274
        throws DataException {
1275
        try {
1276
            if (type == null) {
1277
                throw new NullFeatureTypeException(getName());
1278
            }
1279
            if (mode == MODE_QUERY && type.hasOnlyMetadataChanges(this.defaultFeatureType)) {
1280
                if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled() ) {
1281
                  return;
1282
                }
1283
                FeatureType theType = type.getNotEditableCopy();
1284
                if( defaultFeatureType.getId().equals(theType.getId()) ) {
1285
                    defaultFeatureType = theType;
1286
                }
1287
                List newtypes = new ArrayList();
1288
                for (FeatureType featureType : this.featureTypes) {
1289
                    if( featureType.getId().equals(theType.getId()) ) {
1290
                        newtypes.add(theType);
1291
                    } else {
1292
                        newtypes.add(featureType);
1293
                    }                    
1294
                }
1295
                this.featureTypes = newtypes;
1296
                saveDALFile();
1297
                notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1298
                return ;
1299
            }
1300
            boolean typehasStrongChanges = ((DefaultEditableFeatureType) type).hasStrongChanges();
1301
            if (typehasStrongChanges) {
1302
                checkInEditingMode();
1303
            }  else if(this.isAppending()) {
1304
                throw new NeedEditingModeException(this.getName());
1305
            }
1306
            // FIXME: Comprobar que es un featureType aceptable.
1307
            if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE_TYPE, type).isCanceled() ) {
1308
              return;
1309
            }
1310
            newVersionOfUpdate();
1311
            
1312
            FeatureType oldt = type.getSource().getCopy();
1313
            FeatureType newt = type.getCopy();
1314
            commands.update(newt, oldt);
1315
            if (typehasStrongChanges) { 
1316
                hasStrongChanges = true;
1317
            }
1318
            notifyChange(FeatureStoreNotification.AFTER_UPDATE_TYPE, type);
1319
        } catch (Exception e) {
1320
            throw new StoreUpdateFeatureTypeException(e, this.getName());
1321
        }
1322
    }
1323

    
1324
    @Override
1325
    public void delete(Feature feature) throws DataException {
1326
        this.commands.delete(feature);
1327
    }
1328

    
1329
    synchronized public void doDelete(Feature feature) throws DataException {
1330
        try {
1331
            checkInEditingMode();
1332
            checkIsOwnFeature(feature);
1333
            if (feature instanceof EditableFeature) {
1334
                throw new StoreDeleteEditableFeatureException(getName());
1335
            }
1336
            if( notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled() ) {
1337
              return;
1338
            }
1339

    
1340
            //Update the featureManager and the spatialManager
1341
            featureManager.delete(feature.getReference());
1342
            spatialManager.deleteFeature(feature);
1343

    
1344
            newVersionOfUpdate();
1345
            hasStrongChanges = true;
1346
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1347
        } catch (Exception e) {
1348
            throw new StoreDeleteFeatureException(e, this.getName());
1349
        }
1350
    }
1351

    
1352
    public synchronized void insert(FeatureSet set) throws DataException {
1353
        switch (mode) {
1354
        case MODE_QUERY:
1355
            throw new NeedEditingModeException(this.getName());
1356

    
1357
        case MODE_APPEND:
1358
        case MODE_FULLEDIT:
1359
            break;
1360
        }
1361
        try {
1362
            set.accept((Object obj) -> {
1363
                EditableFeature ef = createNewFeature((Feature) obj);
1364
                insert(ef);
1365
            });
1366
        } catch (BaseException ex) {
1367
            throw new StoreInsertFeatureException(ex, this.getName());
1368
        }
1369
    }
1370
    
1371
    private static EditableFeature lastChangedFeature = null;
1372

    
1373
    @Override
1374
    public synchronized void insert(EditableFeature feature)
1375
        throws DataException {
1376
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1377
        try {
1378
            switch (mode) {
1379
            case MODE_QUERY:
1380
                throw new NeedEditingModeException(this.getName());
1381

    
1382
            case MODE_APPEND:
1383
                checkIsOwnFeature(feature);
1384
                if (feature.getSource() != null) {
1385
                    throw new NoNewFeatureInsertException(this.getName());
1386
                }
1387
                if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1388
                  return;
1389
                }
1390
                this.featureCount = null;
1391
                feature.validate(Feature.UPDATE);
1392
                provider.append(((DefaultEditableFeature) feature).getData());
1393
                hasStrongChanges = true;
1394
                hasInserts = true;
1395
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1396
                break;
1397

    
1398
            case MODE_FULLEDIT:
1399
                if (feature.getSource() != null) {
1400
                    throw new NoNewFeatureInsertException(this.getName());
1401
                }
1402
                feature.validate(Feature.UPDATE);
1403
                commands.insert(feature);
1404
            }
1405
        } catch (Exception e) {
1406
            throw new StoreInsertFeatureException(e, this.getName());
1407
        }
1408
    }
1409

    
1410
    synchronized public void doInsert(EditableFeature feature)
1411
        throws DataException {
1412
        checkIsOwnFeature(feature);
1413

    
1414
        waitForIndexes();
1415

    
1416
        if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1417
          return;
1418
        }
1419
        newVersionOfUpdate();
1420
        if ((lastChangedFeature == null)
1421
            || (lastChangedFeature.getSource() != feature.getSource())) {
1422
            lastChangedFeature = feature;
1423
            feature.validate(Feature.UPDATE);
1424
            lastChangedFeature = null;
1425
        }
1426
        //Update the featureManager and the spatialManager
1427
        ((DefaultEditableFeature) feature).setInserted(true);
1428
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1429

    
1430

    
1431
        featureManager.add(newFeature);
1432
        spatialManager.insertFeature(newFeature);
1433

    
1434
        hasStrongChanges = true;
1435
        hasInserts = true;
1436
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1437
    }
1438

    
1439
    @Override
1440
    public void update(EditableFeature feature)
1441
    throws DataException {
1442
        if ((feature).getSource() == null) {
1443
            insert(feature);
1444
            return;
1445
        }
1446
        commands.update(feature, feature.getSource());
1447
    }
1448

    
1449
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1450
        throws DataException {
1451
        try {
1452
            checkInEditingMode();
1453
            checkIsOwnFeature(feature);
1454
            if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled() ) {
1455
              return;
1456
            }
1457
            newVersionOfUpdate();
1458
            if ((lastChangedFeature == null)
1459
                || (lastChangedFeature.getSource() != feature.getSource())) {
1460
                lastChangedFeature = feature;
1461
                feature.validate(Feature.UPDATE);
1462
                lastChangedFeature = null;
1463
            }
1464

    
1465
            //Update the featureManager and the spatialManager
1466
            Feature newf = feature.getNotEditableCopy();
1467
            featureManager.update(newf, oldFeature);
1468
            spatialManager.updateFeature(newf, oldFeature);
1469

    
1470
            hasStrongChanges = true;
1471
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1472
        } catch (Exception e) {
1473
            throw new StoreUpdateFeatureException(e, this.getName());
1474
        }
1475
    }
1476

    
1477
    @Override
1478
    synchronized public void redo() throws RedoException {
1479
        Command redo = commands.getNextRedoCommand();
1480
        try {
1481
            checkInEditingMode();
1482
        } catch (NeedEditingModeException ex) {
1483
            throw new RedoException(redo, ex);
1484
        }
1485
        if( notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled() ) {
1486
          return;
1487
        }
1488
        newVersionOfUpdate();
1489
        commands.redo();
1490
        hasStrongChanges = true;
1491
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1492
    }
1493

    
1494
    @Override
1495
    synchronized public void undo() throws UndoException {
1496
        Command undo = commands.getNextUndoCommand();
1497
        try {
1498
            checkInEditingMode();
1499
        } catch (NeedEditingModeException ex) {
1500
            throw new UndoException(undo, ex);
1501
        }
1502
        if( notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled() ) {
1503
          return;
1504
        }
1505
        newVersionOfUpdate();
1506
        commands.undo();
1507
        hasStrongChanges = true;
1508
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1509
    }
1510

    
1511
    @Override
1512
    public List getRedoInfos() {
1513
        if (isEditing() && (commands != null)) {
1514
            return commands.getRedoInfos();
1515
        } else {
1516
            return null;
1517
        }
1518
    }
1519

    
1520
    @Override
1521
    public List getUndoInfos() {
1522
        if (isEditing() && (commands != null)) {
1523
            return commands.getUndoInfos();
1524
        } else {
1525
            return null;
1526
        }
1527
    }
1528

    
1529
    public synchronized FeatureCommandsStack getCommandsStack()
1530
        throws DataException {
1531
        checkInEditingMode();
1532
        return commands;
1533
    }
1534

    
1535
    @Override
1536
    synchronized public void cancelEditing() throws DataException {
1537
        if( spatialManager!=null ) {
1538
            spatialManager.cancelModifies();
1539
        }
1540
        try {
1541
            switch (mode) {
1542
            case MODE_QUERY:
1543
                throw new NeedEditingModeException(this.getName());
1544

    
1545
            case MODE_APPEND:
1546
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1547
                  return;
1548
                }
1549
                provider.abortAppend();
1550
                exitEditingMode();
1551
                ((FeatureSelection) this.getSelection()).deselectAll();
1552
                updateIndexes();
1553
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1554

    
1555
            case MODE_FULLEDIT:
1556
                boolean clearSelection = this.hasStrongChanges;
1557
                if (this.selection instanceof FeatureReferenceSelection) {
1558
                    clearSelection = this.hasInserts;
1559
                }
1560
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1561
                  return;
1562
                }
1563
                exitEditingMode();
1564
                if (clearSelection) {
1565
                    ((FeatureSelection) this.getSelection()).deselectAll();
1566
                }
1567
                updateIndexes();
1568
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1569
            }
1570
        } catch (Exception e) {
1571
            throw new StoreCancelEditingException(e, this.getName());
1572
        }
1573
    }
1574

    
1575
    @Override
1576
    synchronized public void finishEditing() throws DataException {
1577
        LOGGER.debug("finish editing of mode: {}", mode);
1578
        try {
1579

    
1580
            /*
1581
             * Selection needs to be cleared when editing stops
1582
             * to prevent conflicts with selection remaining from
1583
             * editing mode.
1584
             */
1585
//            ((FeatureSelection) this.getSelection()).deselectAll();
1586
            Map<String,List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1587
            switch (mode) {
1588
            case MODE_QUERY:
1589
                throw new NeedEditingModeException(this.getName());
1590

    
1591
            case MODE_APPEND:
1592
                if( selection!=null ) {
1593
                    selection = null;
1594
                }
1595
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled() ) {
1596
                  return;
1597
                }
1598
                saveDALFile();
1599
                provider.endAppend();
1600
                exitEditingMode();
1601
                this.updateComputedFields(computedFields);
1602
                loadDALFile();
1603
                updateIndexes();
1604
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1605
                break;
1606

    
1607
            case MODE_FULLEDIT:
1608
                if (hasStrongChanges && !this.allowWrite()) {
1609
                    throw new WriteNotAllowedException(getName());
1610
                }
1611
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, 
1612
                        featureManager.getDeleted(),
1613
                        featureManager.getInsertedFeatures(),
1614
                        featureManager.getUpdatedFeatures(),
1615
                        featureTypeManager.getFeatureTypesChanged().iterator(),
1616
                        featureManager.isSelectionCompromised()).isCanceled() ) {
1617
                  return;
1618
                }
1619
                saveDALFile();
1620
                if(featureManager.isSelectionCompromised() && selection!=null ) {
1621
                    selection = null;
1622
                }
1623
                if (hasStrongChanges) {
1624
                    validateFeatures(Feature.FINISH_EDITING);
1625

    
1626
                    /*
1627
                     * This will throw a PerformEditingExceptionif the provider
1628
                     * does not accept the changes (for example, an invalid field name)
1629
                     */
1630
                    provider.performChanges(featureManager.getDeleted(),
1631
                        featureManager.getInserted(),
1632
                        featureManager.getUpdated(),
1633
                        removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1634
                    
1635
                }  
1636
                this.updateComputedFields(computedFields);
1637
                exitEditingMode();
1638
                loadDALFile();
1639
                updateIndexes();
1640
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1641
                break;
1642
            }
1643
        } catch (PerformEditingException pee) {
1644
            throw new WriteException(provider.getSourceId().toString(), pee);
1645
        } catch (Exception e) {
1646
            throw new FinishEditingException(e);
1647
        }
1648
    }
1649
    private Map<String,List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
1650
        Map<String,List<FeatureAttributeDescriptor>> r = new HashMap<>();
1651
        
1652
        List<FeatureType> theTypes = new ArrayList<>();
1653
        theTypes.addAll(this.getFeatureTypes());
1654
        theTypes.add(this.getDefaultFeatureType());
1655
        for( int n=0; n<theTypes.size(); n++ ) {
1656
            FeatureType type = theTypes.get(n);
1657
                for (FeatureAttributeDescriptor attrdesc : type) {
1658
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
1659
                    if( emulator!= null) {
1660
                        List<FeatureAttributeDescriptor> l = r.get(type.getId());
1661
                        if (l==null) {
1662
                            l = new ArrayList<>();
1663
                            r.put(type.getId(), l);
1664
                        }
1665
                        l.add(attrdesc);
1666
                    }
1667
            }
1668
        }
1669
        return r;
1670
    }
1671
    private void updateComputedFields(Map<String,List<FeatureAttributeDescriptor>> computedFields) throws DataException {
1672

    
1673
        List<FeatureType> theTypes = new ArrayList<>();
1674
        theTypes.addAll(this.getFeatureTypes());
1675
        theTypes.add(this.getDefaultFeatureType());
1676
        for( int n=0; n<theTypes.size(); n++ ) {
1677
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1678
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1679
            if(x!=null && !x.isEmpty()) {
1680
                for (FeatureAttributeDescriptor attrdesc : x) {
1681
                    if (type.get(attrdesc.getName())==null) {
1682
                        type.add(attrdesc);
1683
                    }
1684
                }
1685
            }
1686
        }
1687
        
1688
    }
1689
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
1690
        // FIXME: Falta por implementar
1691
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
1692
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
1693
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
1694
//                if (attributeDescriptor.isComputed()) {
1695
//                    target.remove(attributeDescriptor.getName());
1696
//                }
1697
//            }
1698
//        }
1699
        return ftypes;
1700
    }
1701
    
1702

    
1703
    private void saveDALFile() {       
1704
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1705
        try {
1706
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1707
            if( resourcesStorage == null || resourcesStorage.isReadOnly() ) {
1708
                return;
1709
            }
1710
            resource = resourcesStorage.getResource("dal");
1711
            if( resource == null || resource.isReadOnly() ) {
1712
                return;
1713
            }
1714
            DALFile dalFile = DALFile.getDALFile();
1715
            dalFile.setStore(this);
1716
            if( !dalFile.isEmpty() ) {
1717
                dalFile.write(resource);
1718
            }
1719
        } catch (Throwable ex) {
1720
            LOGGER.warn("Can't save DAL resource", ex);
1721
        } finally {
1722
            IOUtils.closeQuietly(resource);
1723
        }
1724
    }
1725
    
1726
    private void loadDALFile() {
1727
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1728
        try {
1729
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1730
            if( resourcesStorage == null ) {
1731
                return;
1732
            }
1733
            resource = resourcesStorage.getResource("dal");
1734
            if( resource == null || !resource.exists() ) {
1735
                return;
1736
            }
1737
            DALFile dalFile = DALFile.getDALFile(resource);
1738
            if( !dalFile.isEmpty() ) {
1739
                dalFile.updateStore(this);
1740
            }
1741
        } catch (Throwable ex) {
1742
            LOGGER.warn("Can't load DAL resource", ex);
1743
        } finally {
1744
            IOUtils.closeQuietly(resource);
1745
        }
1746
    }
1747
    
1748
    /**
1749
     * Save changes in the provider without leaving the edit mode.
1750
     * Do not call observers to communicate a change of ediding mode.
1751
     * The operation's history is eliminated to prevent inconsistencies
1752
     * in the data.
1753
     *
1754
     * @throws DataException
1755
     */
1756
    @Override
1757
    synchronized public void commitChanges() throws DataException {
1758
      LOGGER.debug("commitChanges of mode: {}", mode);
1759
      if( !canCommitChanges() ) {
1760
              throw new WriteNotAllowedException(getName());
1761
      }
1762
      try {
1763
        switch (mode) {
1764
        case MODE_QUERY:
1765
          throw new NeedEditingModeException(this.getName());
1766

    
1767
        case MODE_APPEND:
1768
          this.provider.endAppend();
1769
          exitEditingMode();
1770
          invalidateIndexes();
1771
          this.provider.beginAppend();
1772
          hasInserts = false;
1773
          break;
1774

    
1775
        case MODE_FULLEDIT:
1776
          if (hasStrongChanges && !this.allowWrite()) {
1777
            throw new WriteNotAllowedException(getName());
1778
          }
1779
          if (hasStrongChanges) {
1780
            validateFeatures(Feature.FINISH_EDITING);
1781
            provider.performChanges(featureManager.getDeleted(),
1782
              featureManager.getInserted(),
1783
              featureManager.getUpdated(),
1784
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1785
          }
1786
          invalidateIndexes();
1787
          featureManager = new FeatureManager();
1788
          featureTypeManager = new FeatureTypeManager(this);
1789
          spatialManager = new SpatialManager(this, provider.getEnvelope());
1790

    
1791
          commands =
1792
            new DefaultFeatureCommandsStack(this, featureManager,
1793
              spatialManager, featureTypeManager);
1794
          featureCount = null;
1795
          hasStrongChanges = false;
1796
          hasInserts = false;
1797
          break;
1798
        }
1799
      } catch (Exception e) {
1800
        throw new FinishEditingException(e);
1801
      }
1802
    }
1803

    
1804
    @Override
1805
    synchronized public boolean canCommitChanges() throws DataException {
1806
        if ( !this.allowWrite()) {
1807
                return false;
1808
        }
1809
            switch (mode) {
1810
            default:
1811
        case MODE_QUERY:
1812
                return false;
1813

    
1814
        case MODE_APPEND:
1815
                return true;
1816

    
1817
        case MODE_FULLEDIT:
1818
            List types = this.getFeatureTypes();
1819
            for( int i=0; i<types.size(); i++ ) {
1820
                    Object type = types.get(i);
1821
                    if( type instanceof DefaultEditableFeatureType ) {
1822
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1823
                                    return false;
1824
                            }
1825
                    }
1826
            }
1827
            return true;
1828
            }
1829
    }
1830

    
1831
    @Override
1832
    public void beginEditingGroup(String description)
1833
        throws NeedEditingModeException {
1834
        checkInEditingMode();
1835
        commands.startComplex(description);
1836
    }
1837

    
1838
    @Override
1839
    public void endEditingGroup() throws NeedEditingModeException {
1840
        checkInEditingMode();
1841
        commands.endComplex();
1842
    }
1843

    
1844
    @Override
1845
    public boolean isAppendModeSupported() {
1846
        return this.provider.supportsAppendMode();
1847
    }
1848

    
1849
    @Override
1850
    public void export(DataServerExplorer explorer, String provider,
1851
        NewFeatureStoreParameters params) throws DataException {
1852

    
1853
        if (this.getFeatureTypes().size() != 1) {
1854
            throw new NotYetImplemented(
1855
                "export whith more than one type not yet implemented");
1856
        }
1857
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1858
        FeatureStore target = null;
1859
        FeatureSet features = null;
1860
        DisposableIterator iterator = null;
1861
        try {
1862
            FeatureType type = this.getDefaultFeatureType();
1863
            if ((params.getDefaultFeatureType() == null)
1864
                || (params.getDefaultFeatureType().size() == 0)) {
1865
                params.setDefaultFeatureType(type.getEditable());
1866

    
1867
            }
1868
            explorer.add(provider, params, true);
1869

    
1870
            DataManager manager = DALLocator.getDataManager();
1871
            target = (FeatureStore) manager.openStore(provider, params);
1872
            FeatureType targetType = target.getDefaultFeatureType();
1873

    
1874
            target.edit(MODE_APPEND);
1875
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
1876
            if (featureSelection.getSize() > 0) {
1877
                features = this.getFeatureSelection();
1878
            } else {
1879
                if ((pkattrs != null) && (pkattrs.length > 0)) {
1880
                    FeatureQuery query = createFeatureQuery();
1881
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
1882
                        query.getOrder().add(pkattr.getName(), true);
1883
                    }
1884
                    features = this.getFeatureSet(query);
1885
                } else {
1886
                    features = this.getFeatureSet();
1887
                }
1888
            }
1889
            iterator = features.fastIterator();
1890
            while (iterator.hasNext()) {
1891
                DefaultFeature feature = (DefaultFeature) iterator.next();
1892
                target.insert(target.createNewFeature(targetType, feature));
1893
            }
1894
            target.finishEditing();
1895
            target.dispose();
1896
        } catch (Exception e) {
1897
            throw new DataExportException(e, params.toString());
1898
        } finally {
1899
            dispose(iterator);
1900
            dispose(features);
1901
            dispose(target);
1902
        }
1903
    }
1904

    
1905
    public void copyTo(final FeatureStore target) {
1906
        boolean finishEditingAtEnd = false;
1907
        try {
1908
            if( !target.isEditing() && !target.isAppending() ) {
1909
                finishEditingAtEnd = true;
1910
                target.edit(MODE_APPEND);
1911
            }
1912
            this.accept(new Visitor() {
1913
                @Override
1914
                public void visit(Object obj) throws VisitCanceledException, BaseException {
1915
                    Feature f_src = (Feature) obj;
1916
                    EditableFeature f_dst = target.createNewFeature(f_src);
1917
                    target.insert(f_dst);
1918
                }
1919
            });
1920
            if( finishEditingAtEnd ) {
1921
                target.finishEditing();
1922
            }
1923
            
1924
        } catch(Exception ex) {
1925
            try {
1926
                if( finishEditingAtEnd ) {
1927
                    target.cancelEditing();
1928
                }
1929
            } catch (Exception ex1) {
1930
            }
1931
            throw new RuntimeException("Can't copy store.",ex);
1932
        }
1933
            
1934
    }
1935
    
1936
    //
1937
    // ====================================================================
1938
    // Obtencion de datos
1939
    // getDataCollection, getFeatureCollection
1940
    //
1941

    
1942
    @Override
1943
    public DataSet getDataSet() throws DataException {
1944
        checkNotInAppendMode();
1945
        FeatureQuery query =
1946
            new DefaultFeatureQuery(this.getDefaultFeatureType());
1947
        return new DefaultFeatureSet(this, query);
1948
    }
1949

    
1950
    @Override
1951
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
1952
        checkNotInAppendMode();
1953
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
1954
    }
1955

    
1956
    @Override
1957
    public void getDataSet(Observer observer) throws DataException {
1958
        checkNotInAppendMode();
1959
        this.getFeatureSet(null, observer);
1960
    }
1961

    
1962
    @Override
1963
    public void getDataSet(DataQuery dataQuery, Observer observer)
1964
        throws DataException {
1965
        checkNotInAppendMode();
1966
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
1967
    }
1968

    
1969
    @Override
1970
    public FeatureSet getFeatureSet() throws DataException {
1971
        return this.getFeatureSet((FeatureQuery)null);
1972
    }
1973

    
1974
    @Override
1975
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
1976
        throws DataException {
1977
        checkNotInAppendMode();
1978
        if( featureQuery==null ) {
1979
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
1980
        }
1981
        return new DefaultFeatureSet(this, featureQuery);
1982
    }
1983

    
1984
    @Override
1985
    public FeatureSet getFeatureSet(String filter) throws DataException {
1986
        return this.getFeatureSet(filter, null, true);
1987
    }
1988

    
1989
    @Override
1990
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
1991
        return this.getFeatureSet(filter, sortBy, true);
1992
    }
1993

    
1994
    @Override
1995
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
1996
        return this.getFeatureSet(filter, null, true);
1997
    }
1998
    
1999
    @Override
2000
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2001
        return this.getFeatureSet(filter, sortBy, true);
2002
    }
2003

    
2004
    @Override
2005
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2006
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2007
        return this.getFeatureSet(query);
2008
    }
2009
    
2010
    @Override
2011
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2012
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2013
        return this.getFeatureSet(query);
2014
    }
2015
    
2016
    @Override
2017
    public List<Feature> getFeatures(String filter)  {
2018
        return this.getFeatures(filter, null, true);
2019
    }
2020

    
2021
    @Override
2022
    public List<Feature> getFeatures(String filter, String sortBy)  {
2023
        return this.getFeatures(filter, sortBy, true);
2024
    }
2025

    
2026
    @Override
2027
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
2028
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2029
        return this.getFeatures(query, 0);
2030
    }
2031
    
2032
    @Override
2033
    public List<Feature> getFeatures(Expression filter)  {
2034
        return this.getFeatures(filter, null, true);
2035
    }
2036

    
2037
    @Override
2038
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
2039
        return this.getFeatures(filter, sortBy, true);
2040
    }
2041

    
2042
    @Override
2043
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
2044
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2045
        return this.getFeatures(query, 0);
2046
    }
2047
    
2048
    @Override
2049
    public List<Feature> getFeatures(FeatureQuery query)  {
2050
        return this.getFeatures(query, 0);
2051
    }
2052
    
2053
    @Override
2054
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
2055
        try {
2056
            if( pageSize<=0 ) {
2057
                pageSize = 100;
2058
            }
2059
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2060
            return pager.asList();
2061
        } catch (BaseException ex) {
2062
            throw new RuntimeException("Can't create the list of features.", ex);
2063
        }
2064
    }
2065

    
2066
    @Override
2067
    public List<Feature> getFeatures() {
2068
        return this.getFeatures(null, 0);
2069
    }
2070

    
2071
    @Override
2072
    public Feature first() throws DataException {
2073
        return this.findFirst((FeatureQuery)null);
2074
    }
2075
    
2076
    @Override
2077
    public Feature findFirst(String filter) throws DataException {
2078
        return this.findFirst(filter, (String)null, true);
2079
    }
2080

    
2081
    @Override
2082
    public Feature findFirst(String filter, String sortBy) throws DataException {
2083
        return this.findFirst(filter, sortBy, true);
2084
    }
2085

    
2086
    @Override
2087
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2088
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2089
        return findFirst(query);
2090
    }
2091

    
2092
    @Override
2093
    public Feature findFirst(String filter, Expression sortBy, boolean asc) throws DataException {
2094
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2095
        return findFirst(query);
2096
    }
2097
    
2098
    @Override
2099
    public Feature findFirst(Expression filter) throws DataException {
2100
        return this.findFirst(filter, (String)null, true);
2101
    }
2102

    
2103
    @Override
2104
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2105
        return this.findFirst(filter, sortBy, true);
2106
    }
2107

    
2108
    @Override
2109
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2110
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2111
        return findFirst(query);
2112
    }
2113
    
2114
    @Override
2115
    public Feature findFirst(Expression filter, Expression sortBy, boolean asc) throws DataException {
2116
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2117
        return findFirst(query);
2118
    }
2119
    
2120
    @Override
2121
    public Feature findFirst(FeatureQuery query) throws DataException {
2122
        if( query == null ) {
2123
            query = this.createFeatureQuery();
2124
        } else {
2125
            query = query.getCopy();
2126
        }
2127
        query.setLimit(1);
2128
        final MutableObject<Feature> feature = new MutableObject<>();
2129
        try {
2130
            this.accept(new Visitor() {
2131
                @Override
2132
                public void visit(Object obj) throws VisitCanceledException, BaseException {
2133
                    feature.setValue((Feature) obj);
2134
                    throw new VisitCanceledException();
2135
                }
2136
            }, query);
2137
        } catch(VisitCanceledException ex) {
2138

    
2139
        } catch(DataException ex) {
2140
            throw ex;
2141
        } catch(Exception ex) {
2142
            throw new RuntimeException("", ex);
2143
        }
2144
        return feature.getValue();
2145
    }
2146

    
2147
    @Override
2148
    public void accept(Visitor visitor) throws BaseException {
2149
        this.accept(visitor, null);
2150
    }
2151

    
2152
    @Override
2153
    public void accept(Visitor visitor, DataQuery dataQuery)
2154
        throws BaseException {
2155
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2156
        try {
2157
            set.accept(visitor);
2158
        } finally {
2159
            set.dispose();
2160
        }
2161
    }
2162

    
2163
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2164
        throws DataException {
2165
        DefaultFeatureType fType =
2166
            (DefaultFeatureType) this.getFeatureType(featureQuery
2167
                .getFeatureTypeId());
2168
        if( featureQuery.hasAttributeNames() || 
2169
            featureQuery.hasConstantsAttributeNames() ||
2170
            fType.hasRequiredFields()    
2171
            ) {
2172
            if( featureQuery.hasGroupByColumns()) {
2173
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2174
            } else {
2175
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2176
            }
2177
        }
2178
        return fType;
2179
    }
2180

    
2181
    @Override
2182
    public void getFeatureSet(Observer observer) throws DataException {
2183
        checkNotInAppendMode();
2184
        this.getFeatureSet(null, observer);
2185
    }
2186

    
2187
    @Override
2188
    public void getFeatureSet(FeatureQuery query, Observer observer)
2189
        throws DataException {
2190
        class LoadInBackGround implements Runnable {
2191

    
2192
            private final FeatureStore store;
2193
            private final FeatureQuery query;
2194
            private final Observer observer;
2195

    
2196
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2197
                Observer observer) {
2198
                this.store = store;
2199
                this.query = query;
2200
                this.observer = observer;
2201
            }
2202

    
2203
            void notify(FeatureStoreNotification theNotification) {
2204
                observer.update(store, theNotification);
2205
            }
2206

    
2207
            @Override
2208
            public void run() {
2209
                FeatureSet set = null;
2210
                try {
2211
                    set = store.getFeatureSet(query);
2212
                    notify(new DefaultFeatureStoreNotification(store,
2213
                        FeatureStoreNotification.LOAD_FINISHED, set));
2214
                } catch (Exception e) {
2215
                    notify(new DefaultFeatureStoreNotification(store,
2216
                        FeatureStoreNotification.LOAD_FINISHED, e));
2217
                } finally {
2218
                    dispose(set);
2219
                }
2220
            }
2221
        }
2222

    
2223
        checkNotInAppendMode();
2224
        if (query == null) {
2225
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2226
        }
2227
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2228
        Thread thread = new Thread(task, "Load Feature Set in background");
2229
        thread.start();
2230
    }
2231

    
2232
    @Override
2233
    public Feature getFeatureByReference(FeatureReference reference)
2234
        throws DataException {
2235
        checkNotInAppendMode();
2236
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
2237
        FeatureType featureType;
2238
        if (ref.getFeatureTypeId() == null) {
2239
            featureType = this.getDefaultFeatureType();
2240
        } else {
2241
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2242
        }
2243
        return this.getFeatureByReference(reference, featureType);
2244
    }
2245

    
2246
    @Override
2247
    public Feature getFeatureByReference(FeatureReference reference,
2248
        FeatureType featureType) throws DataException {
2249
        checkNotInAppendMode();
2250
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2251
        if (this.mode == MODE_FULLEDIT) {
2252
            Feature f = featureManager.get(reference, this, featureType);
2253
            if (f != null) {
2254
                return f;
2255
            }
2256
        }
2257

    
2258
        FeatureType sourceFeatureType = featureType;
2259
        if (!this.transforms.isEmpty()) {
2260
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2261
        }
2262
        // TODO comprobar que el id es de este store
2263

    
2264
        DefaultFeature feature =
2265
            new DefaultFeature(this,
2266
                this.provider.getFeatureProviderByReference(
2267
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2268

    
2269
        if (!this.transforms.isEmpty()) {
2270
            return this.transforms.applyTransform(feature, featureType);
2271
        }
2272
        return feature;
2273
    }
2274

    
2275
    //
2276
    // ====================================================================
2277
    // Gestion de features
2278
    //
2279

    
2280
    private FeatureType fixFeatureType(DefaultFeatureType type)
2281
        throws DataException {
2282
        FeatureType original = this.getDefaultFeatureType();
2283

    
2284
        if ((type == null) || type.equals(original)) {
2285
            return original;
2286
        } else {
2287
            if (!type.isSubtypeOf(original)) {
2288
                Iterator iter = this.getFeatureTypes().iterator();
2289
                FeatureType tmpType;
2290
                boolean found = false;
2291
                while (iter.hasNext()) {
2292
                    tmpType = (FeatureType) iter.next();
2293
                    if (type.equals(tmpType)) {
2294
                        return type;
2295

    
2296
                    } else
2297
                        if (type.isSubtypeOf(tmpType)) {
2298
                            found = true;
2299
                            original = tmpType;
2300
                            break;
2301
                        }
2302

    
2303
                }
2304
                if (!found) {
2305
                    throw new IllegalFeatureTypeException(getName());
2306
                }
2307
            }
2308
        }
2309

    
2310
        // Checks that type has all fields of pk
2311
        // else add the missing attributes at the end.
2312
        if (!original.hasOID()) {
2313
            // Gets original pk attributes
2314
            DefaultEditableFeatureType edOriginal =
2315
                (DefaultEditableFeatureType) original.getEditable();
2316
            FeatureAttributeDescriptor orgAttr;
2317
            Iterator edOriginalIter = edOriginal.iterator();
2318
            while (edOriginalIter.hasNext()) {
2319
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2320
                if (!orgAttr.isPrimaryKey()) {
2321
                    edOriginalIter.remove();
2322
                }
2323
            }
2324

    
2325
            // Checks if all pk attributes are in type
2326
            Iterator typeIterator;
2327
            edOriginalIter = edOriginal.iterator();
2328
            FeatureAttributeDescriptor attr;
2329
            while (edOriginalIter.hasNext()) {
2330
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2331
                typeIterator = type.iterator();
2332
                while (typeIterator.hasNext()) {
2333
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2334
                    if (attr.getName().equals(orgAttr.getName())) {
2335
                        edOriginalIter.remove();
2336
                        break;
2337
                    }
2338
                }
2339
            }
2340

    
2341
            // add missing pk attributes if any
2342
            if (edOriginal.size() > 0) {
2343
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2344
                DefaultEditableFeatureType edType =
2345
                    (DefaultEditableFeatureType) original.getEditable();
2346
                edType.clear();
2347
                edType.addAll(type);
2348
                edType.addAll(edOriginal);
2349
                if (!isEditable) {
2350
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2351
                }
2352
            }
2353

    
2354
        }
2355

    
2356
        return type;
2357
    }
2358

    
2359
    @Override
2360
    public void validateFeatures(int mode) throws DataException {
2361
        FeatureSet collection = null;
2362
        DisposableIterator iter = null;
2363
        try {
2364
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2365
            if( rules==null || rules.isEmpty() ) {
2366
                return;
2367
            }
2368
            checkNotInAppendMode();
2369
            collection = this.getFeatureSet();
2370
            iter = collection.fastIterator();
2371
            long previousVersionOfUpdate = currentVersionOfUpdate();
2372
            while (iter.hasNext()) {
2373
                ((DefaultFeature) iter.next()).validate(mode);
2374
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2375
                    throw new ConcurrentDataModificationException(getName());
2376
                }
2377
            }
2378
        } catch (Exception e) {
2379
            throw new ValidateFeaturesException(e, getName());
2380
        } finally {
2381
            DisposeUtils.disposeQuietly(iter);
2382
            DisposeUtils.disposeQuietly(collection);
2383
        }
2384
    }
2385

    
2386
    @Override
2387
    public FeatureType getDefaultFeatureType() throws DataException {
2388
        try {
2389

    
2390
            if (isEditing()) {
2391
                FeatureType auxFeatureType =
2392
                    featureTypeManager.getType(defaultFeatureType.getId());
2393
                if (auxFeatureType != null) {
2394
                    return avoidEditable(auxFeatureType);
2395
                }
2396
            }
2397
            FeatureType type = this.transforms.getDefaultFeatureType();
2398
                if (type != null) {
2399
                return avoidEditable(type);
2400
                }
2401

    
2402
            return avoidEditable(defaultFeatureType);
2403

    
2404
        } catch (Exception e) {
2405
            throw new GetFeatureTypeException(e, getName());
2406
        }
2407
    }
2408

    
2409
    @Override
2410
    public FeatureType getDefaultFeatureTypeQuietly() {
2411
      try {
2412
        return this.getDefaultFeatureType();
2413
      } catch(Exception ex) {
2414
        return null;
2415
      }
2416
    }
2417
    
2418
    private FeatureType avoidEditable(FeatureType ft) {
2419
        if (ft instanceof EditableFeatureType) {
2420
            return ((EditableFeatureType) ft).getNotEditableCopy();
2421
        } else {
2422
            return ft;
2423
        }
2424
    }
2425

    
2426
    @Override
2427
    public FeatureType getFeatureType(String featureTypeId)
2428
        throws DataException {
2429
        if (featureTypeId == null) {
2430
            return this.getDefaultFeatureType();
2431
        }
2432
        try {
2433
            if (isEditing()) {
2434
                FeatureType auxFeatureType =
2435
                    featureTypeManager.getType(featureTypeId);
2436
                if (auxFeatureType != null) {
2437
                    return auxFeatureType;
2438
                }
2439
            }
2440
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2441
            if (type != null) {
2442
                return type;
2443
            }
2444
            Iterator iter = this.featureTypes.iterator();
2445
            while (iter.hasNext()) {
2446
                type = (FeatureType) iter.next();
2447
                if (type.getId().equals(featureTypeId)) {
2448
                    return type;
2449
                }
2450
            }
2451
            return null;
2452
        } catch (Exception e) {
2453
            throw new GetFeatureTypeException(e, getName());
2454
        }
2455
    }
2456

    
2457
    public FeatureType getProviderDefaultFeatureType() {
2458
        return defaultFeatureType;
2459
    }
2460

    
2461
    @Override
2462
    public List getFeatureTypes() throws DataException {
2463
        try {
2464
            List types;
2465
            if (isEditing()) {
2466
                types = new ArrayList();
2467
                Iterator it = featureTypes.iterator();
2468
                while (it.hasNext()) {
2469
                    FeatureType type = (FeatureType) it.next();
2470
                    FeatureType typeaux =
2471
                        featureTypeManager.getType(type.getId());
2472
                    if (typeaux != null) {
2473
                        types.add(typeaux);
2474
                    } else {
2475
                        types.add(type);
2476
                    }
2477
                }
2478
                it = featureTypeManager.newsIterator();
2479
                while (it.hasNext()) {
2480
                    FeatureType type = (FeatureType) it.next();
2481
                    types.add(type);
2482
                }
2483
            } else {
2484
                types = this.transforms.getFeatureTypes();
2485
                if (types == null) {
2486
                    types = featureTypes;
2487
                }
2488
            }
2489
            return Collections.unmodifiableList(types);
2490
        } catch (Exception e) {
2491
            throw new GetFeatureTypeException(e, getName());
2492
        }
2493
    }
2494

    
2495
    public List getProviderFeatureTypes() throws DataException {
2496
        return Collections.unmodifiableList(this.featureTypes);
2497
    }
2498

    
2499
    @Override
2500
    public Feature createFeature(FeatureProvider data) throws DataException {
2501
        DefaultFeature feature = new DefaultFeature(this, data);
2502
        return feature;
2503
    }
2504

    
2505
    public Feature createFeature(FeatureProvider data, FeatureType type)
2506
        throws DataException {
2507
        // FIXME: falta por implementar
2508
        // Comprobar si es un subtipo del feature de data
2509
        // y construir un feature usando el subtipo.
2510
        // Probablemente requiera generar una copia del data.
2511
        throw new NotYetImplemented();
2512
    }
2513

    
2514
    @Override
2515
    public EditableFeature createNewFeature(FeatureType type,
2516
        Feature defaultValues) throws DataException {
2517
        try {
2518
            FeatureProvider data = createNewFeatureProvider(type);
2519
            DefaultEditableFeature feature =
2520
                new DefaultEditableFeature(this, data);
2521
            feature.initializeValues(defaultValues);
2522
            data.setNew(true);
2523

    
2524
            return feature;
2525
        } catch (Exception e) {
2526
            throw new CreateFeatureException(e, getName());
2527
        }
2528
    }
2529

    
2530
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2531
        throws DataException {
2532
        type = this.fixFeatureType((DefaultFeatureType) type);
2533
        FeatureProvider data = this.provider.createFeatureProvider(type);
2534
        data.setNew(true);
2535
        if (type.hasOID() && (data.getOID() == null)) {
2536
            data.setOID(this.provider.createNewOID());
2537
        } else {
2538
            data.setOID(this.getTemporalOID());
2539
        }
2540
        return data;
2541

    
2542
    }
2543

    
2544
    @Override
2545
    public EditableFeature createNewFeature(FeatureType type,
2546
        boolean defaultValues) throws DataException {
2547
        try {
2548
            FeatureProvider data = createNewFeatureProvider(type);
2549
            DefaultEditableFeature feature =
2550
                new DefaultEditableFeature(this, data);
2551
            if (defaultValues) {
2552
                feature.initializeValues();
2553
            }
2554
            return feature;
2555
        } catch (Exception e) {
2556
            throw new CreateFeatureException(e, getName());
2557
        }
2558
    }
2559

    
2560
    @Override
2561
    public EditableFeature createNewFeature(boolean defaultValues)
2562
        throws DataException {
2563
        return this.createNewFeature(this.getDefaultFeatureType(),
2564
            defaultValues);
2565
    }
2566

    
2567
    @Override
2568
    public EditableFeature createNewFeature() throws DataException {
2569
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2570
    }
2571

    
2572
    @Override
2573
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2574
        FeatureType ft = this.getDefaultFeatureType();
2575
        EditableFeature f = this.createNewFeature(ft, false);
2576
        f.copyFrom(defaultValues);
2577
        return f;
2578
    }
2579

    
2580
    @Override
2581
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2582
        FeatureType ft = this.getDefaultFeatureType();
2583
        EditableFeature f = this.createNewFeature(ft, false);
2584
        f.copyFrom(defaultValues);
2585
        return f;
2586
    }
2587

    
2588
    @Override
2589
    public EditableFeatureType createFeatureType() {
2590
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2591
        return ftype;
2592
    }
2593

    
2594
    @Override
2595
    public EditableFeatureType createFeatureType(String id) {
2596
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2597
        return ftype;
2598
    }
2599

    
2600
    //
2601
    // ====================================================================
2602
    // Index related methods
2603
    //
2604

    
2605
    @Override
2606
    public FeatureIndexes getIndexes() {
2607
        return this.indexes;
2608
    }
2609

    
2610
    @Override
2611
    public FeatureIndex createIndex(FeatureType featureType,
2612
        String attributeName, String indexName) throws DataException {
2613
        return createIndex(null, featureType, attributeName, indexName);
2614
    }
2615

    
2616
    @Override
2617
    public FeatureIndex createIndex(String indexTypeName,
2618
        FeatureType featureType, String attributeName, String indexName)
2619
        throws DataException {
2620

    
2621
        return createIndex(indexTypeName, featureType, attributeName,
2622
            indexName, false, null);
2623
    }
2624

    
2625
    @Override
2626
    public FeatureIndex createIndex(FeatureType featureType,
2627
        String attributeName, String indexName, Observer observer)
2628
        throws DataException {
2629
        return createIndex(null, featureType, attributeName, indexName,
2630
            observer);
2631
    }
2632

    
2633
    @Override
2634
    public FeatureIndex createIndex(String indexTypeName,
2635
        FeatureType featureType, String attributeName, String indexName,
2636
        final Observer observer) throws DataException {
2637

    
2638
        return createIndex(indexTypeName, featureType, attributeName,
2639
            indexName, true, observer);
2640
    }
2641

    
2642
    private FeatureIndex createIndex(String indexTypeName,
2643
        FeatureType featureType, String attributeName, String indexName,
2644
        boolean background, final Observer observer) throws DataException {
2645

    
2646
        checkNotInAppendMode();
2647
        FeatureIndexProviderServices index;
2648
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2649
                featureType, indexName,
2650
                featureType.getAttributeDescriptor(attributeName));
2651

    
2652
        try {
2653
            index.fill(background, observer);
2654
        } catch (FeatureIndexException e) {
2655
            throw new InitializeException(index.getName(), e);
2656
        }
2657

    
2658
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2659
        return index;
2660
    }
2661

    
2662
    //
2663
    // ====================================================================
2664
    // Transforms related methods
2665
    //
2666

    
2667
    @Override
2668
    public FeatureStoreTransforms getTransforms() {
2669
        return this.transforms;
2670
    }
2671

    
2672
    @Override
2673
    public FeatureQuery createFeatureQuery() {
2674
        return new DefaultFeatureQuery();
2675
    }
2676
    
2677
    @Override
2678
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
2679
        FeatureQuery query = null;
2680
        if( filter!=null ) {
2681
            query = this.createFeatureQuery();
2682
            query.setFilter(filter);
2683
        }
2684
        if( !StringUtils.isEmpty(sortBy) ) {
2685
            if( query == null ) {
2686
                query = this.createFeatureQuery();
2687
            }
2688
            if ( StringUtils.containsAny(sortBy, "(", ")") ) {
2689
                throw new IllegalArgumentException("Incorrect sortBy expression");
2690
            }
2691
            String[] attrnames;
2692
            if( sortBy.contains(",") ) {
2693
                attrnames = StringUtils.split(sortBy, ",");
2694
            } else {
2695
                attrnames = new String[] { sortBy };
2696
            }
2697
            for (String attrname : attrnames) {
2698
                attrname = attrname.trim();
2699
                if( attrname.startsWith("-") ) {
2700
                    query.getOrder().add(sortBy.substring(1).trim(), false);
2701
                } else if( attrname.endsWith("-") ) { 
2702
                    query.getOrder().add(sortBy.substring(0,sortBy.length()-1).trim(), false);
2703
                } else if( attrname.startsWith("+") ) {
2704
                    query.getOrder().add(sortBy.substring(1).trim(), true);
2705
                } else if( attrname.endsWith("-") ) { 
2706
                    query.getOrder().add(sortBy.substring(0,sortBy.length()-1).trim(), true);
2707
                } else {
2708
                    query.getOrder().add(sortBy, asc);
2709
                }
2710
            }
2711
        }
2712
        if( query != null ) {
2713
            query.retrievesAllAttributes();
2714
        }
2715
        return query;
2716
    }
2717
    
2718
    @Override
2719
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
2720
        if( StringUtils.isBlank(filter) ) {
2721
            return this.createFeatureQuery(
2722
                    (Expression)null, 
2723
                    sortBy, 
2724
                    asc
2725
            );
2726
        } else {
2727
            return this.createFeatureQuery(
2728
                    ExpressionUtils.createExpression(filter), 
2729
                    sortBy, 
2730
                    asc
2731
            );
2732
        }
2733
    }
2734
    
2735
    public FeatureQuery createFeatureQuery(Expression filter, Expression sortBy, boolean asc) {
2736
        FeatureQuery query = null;
2737
        if( filter != null ) {
2738
            query = this.createFeatureQuery();
2739
            query.setFilter(filter);
2740
        }
2741
        if( sortBy !=  null) {
2742
            if( query == null ) {
2743
                query = this.createFeatureQuery();
2744
            }
2745
            query.getOrder().add(sortBy, asc);
2746
        }
2747
        
2748
        if( query != null ) {
2749
            query.retrievesAllAttributes();
2750
        }
2751
        return query;
2752
    }
2753
    
2754
    public FeatureQuery createFeatureQuery(String filter, Expression sortBy, boolean asc) {
2755
        if( StringUtils.isBlank(filter) ) {
2756
            return this.createFeatureQuery(
2757
                    (Expression)null, 
2758
                    sortBy, 
2759
                    asc
2760
            );
2761
        } else {
2762
            return this.createFeatureQuery(
2763
                    ExpressionUtils.createExpression(filter), 
2764
                    sortBy, 
2765
                    asc
2766
            );
2767
        }
2768
    }
2769
    
2770
    @Override
2771
    public DataQuery createQuery() {
2772
        return createFeatureQuery();
2773
    }
2774

    
2775
    //
2776
    // ====================================================================
2777
    // UndoRedo related methods
2778
    //
2779

    
2780
    @Override
2781
    public boolean canRedo() {
2782
        return commands.canRedo();
2783
    }
2784

    
2785
    @Override
2786
    public boolean canUndo() {
2787
        return commands.canUndo();
2788
    }
2789

    
2790
    @Override
2791
    public void redo(int num) throws RedoException {
2792
        for (int i = 0; i < num; i++) {
2793
            redo();
2794
        }
2795
    }
2796

    
2797
    @Override
2798
    public void undo(int num) throws UndoException {
2799
        for (int i = 0; i < num; i++) {
2800
            undo();
2801
        }
2802
    }
2803

    
2804
    //
2805
    // ====================================================================
2806
    // Metadata related methods
2807
    //
2808

    
2809
    @Override
2810
    public Object getMetadataID() {
2811
        return this.provider.getSourceId();
2812
    }
2813

    
2814
    @Override
2815
    public void delegate(DynObject dynObject) {
2816
        this.metadata.delegate(dynObject);
2817
    }
2818

    
2819
    @Override
2820
    public DynClass getDynClass() {
2821
        return this.metadata.getDynClass();
2822
    }
2823

    
2824
    @Override
2825
    public Object getDynValue(String name) throws DynFieldNotFoundException {
2826
        try {
2827
            if (this.transforms.hasDynValue(name)) {
2828
                return this.transforms.getDynValue(name);
2829
            }
2830
            if (this.metadata.hasDynValue(name)) {
2831
                return this.metadata.getDynValue(name);
2832
            }
2833
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2834
                return this.provider.getProviderName();
2835
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2836
                return this.provider.getSourceId();
2837
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2838
                try {
2839
                    return this.getDefaultFeatureType();
2840
                } catch (DataException e) {
2841
                    return null;
2842
                }
2843
            }
2844
            return this.metadata.getDynValue(name);
2845
        } catch(Exception ex ) {
2846
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
2847
            return null;
2848
        }
2849
    }
2850

    
2851
    @Override
2852
    public boolean hasDynValue(String name) {
2853
        if (this.transforms.hasDynValue(name)) {
2854
            return true;
2855
        }
2856
        return this.metadata.hasDynValue(name);
2857
    }
2858

    
2859
    @Override
2860
    public boolean hasDynMethod(String name) {
2861
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2862
    }
2863

    
2864
    @Override
2865
    public void implement(DynClass dynClass) {
2866
        this.metadata.implement(dynClass);
2867
    }
2868

    
2869
    @Override
2870
    public Object invokeDynMethod(String name, Object[] args)
2871
        throws DynMethodException {
2872
        return this.metadata.invokeDynMethod(this, name, args);
2873
    }
2874

    
2875
    @Override
2876
    public Object invokeDynMethod(int code, Object[] args)
2877
        throws DynMethodException {
2878
        return this.metadata.invokeDynMethod(this, code, args);
2879
    }
2880

    
2881
    @Override
2882
    public void setDynValue(String name, Object value)
2883
        throws DynFieldNotFoundException {
2884
                if( this.transforms.hasDynValue(name) ) {
2885
                        this.transforms.setDynValue(name, value);
2886
                        return;
2887
                }
2888
        this.metadata.setDynValue(name, value);
2889

    
2890
    }
2891

    
2892
    /*
2893
     * (non-Javadoc)
2894
     *
2895
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2896
     */
2897
    @Override
2898
    public Set getMetadataChildren() {
2899
        return this.metadataChildren;
2900
    }
2901

    
2902
    /*
2903
     * (non-Javadoc)
2904
     *
2905
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2906
     */
2907
    @Override
2908
    public String getMetadataName() {
2909
        return this.provider.getProviderName();
2910
    }
2911

    
2912
    public FeatureTypeManager getFeatureTypeManager() {
2913
        return this.featureTypeManager;
2914
    }
2915

    
2916
    @Override
2917
    public long getFeatureCount() throws DataException {
2918
        if (featureCount == null) {
2919
            featureCount = this.provider.getFeatureCount();
2920
        }
2921
        if (this.isEditing()) {
2922
            if(this.isAppending()) {
2923
                try{
2924
                    throw new IllegalStateException();
2925
                } catch(IllegalStateException e) {
2926
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
2927
                }
2928
                return -1;
2929
            } else {
2930
                return featureCount
2931
                    + this.featureManager.getDeltaSize();
2932
            }
2933
        }
2934
        return featureCount;
2935
    }
2936

    
2937
    private Long getTemporalOID() {
2938
        return this.temporalOid++;
2939
    }
2940

    
2941
    @Override
2942
    public FeatureType getProviderFeatureType(String featureTypeId) {
2943
        if (featureTypeId == null) {
2944
            return this.defaultFeatureType;
2945
        }
2946
        FeatureType type;
2947
        Iterator iter = this.featureTypes.iterator();
2948
        while (iter.hasNext()) {
2949
            type = (FeatureType) iter.next();
2950
            if (type.getId().equals(featureTypeId)) {
2951
                return type;
2952
            }
2953
        }
2954
        return null;
2955
    }
2956

    
2957
    @Override
2958
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
2959
        return ((DefaultFeature) feature).getData();
2960
    }
2961

    
2962
    @Override
2963
    public DataStore getStore() {
2964
        return this;
2965
    }
2966

    
2967
    @Override
2968
    public FeatureStore getFeatureStore() {
2969
        return this;
2970
    }
2971

    
2972
    @Override
2973
    public void createCache(String name, DynObject parameters)
2974
        throws DataException {
2975
        cache = dataManager.createFeatureCacheProvider(name, parameters);
2976
        if (cache == null) {
2977
            throw new CreateException("FeaureCacheProvider", null);
2978
        }
2979
        cache.apply(this, provider);
2980
        provider = cache;
2981

    
2982
        featureCount = null;
2983
    }
2984

    
2985
    @Override
2986
    public FeatureCache getCache() {
2987
        return cache;
2988
    }
2989

    
2990
    @Override
2991
    public void clear() {
2992
        if (metadata != null) {
2993
            metadata.clear();
2994
        }
2995
    }
2996

    
2997
    @Override
2998
    public String getName() {
2999
        if( this.provider != null ) {
3000
            return this.provider.getName();
3001
        }
3002
        if( this.parameters instanceof HasAFile ) {
3003
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
3004
        }
3005
        return "unknow";
3006
    }
3007

    
3008
    @Override
3009
    public String getFullName() {
3010
        try {
3011
            if( this.provider!=null ) {
3012
                return this.provider.getFullName();
3013
            }
3014
            if( this.parameters instanceof HasAFile ) {
3015
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
3016
            }
3017
            return null;
3018
        } catch(Throwable th) {
3019
            return null;
3020
        }
3021
    }
3022

    
3023
    @Override
3024
    public String getProviderName() {
3025
        if( this.provider!=null ) {
3026
            return this.provider.getProviderName();
3027
        }
3028
        if( this.parameters != null ) {
3029
            return this.parameters.getDataStoreName();
3030
        }
3031
        return null;
3032

    
3033
    }
3034

    
3035
    @Override
3036
    public boolean isKnownEnvelope() {
3037
        return this.provider.isKnownEnvelope();
3038
    }
3039

    
3040
    @Override
3041
    public boolean hasRetrievedFeaturesLimit() {
3042
        return this.provider.hasRetrievedFeaturesLimit();
3043
    }
3044

    
3045
    @Override
3046
    public int getRetrievedFeaturesLimit() {
3047
        return this.provider.getRetrievedFeaturesLimit();
3048
    }
3049

    
3050
    @Override
3051
    public Interval getInterval() {
3052
        if( this.timeSupport!=null ) {
3053
            return this.timeSupport.getInterval();
3054
        }
3055
        try {
3056
            FeatureType type = this.getDefaultFeatureType();
3057
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3058
            if( attr!=null ) {
3059
                Interval interval = attr.getInterval();
3060
                if( interval!=null ) {
3061
                    return interval;
3062
                }
3063
            }
3064
        } catch (DataException ex) {
3065
        }
3066
        return this.provider.getInterval();
3067
    }
3068

    
3069
    @Override
3070
    public Collection getTimes() {
3071
        if( this.timeSupport!=null ) {
3072
            return this.timeSupport.getTimes();
3073
        }
3074
        return this.provider.getTimes();
3075
    }
3076

    
3077
    @Override
3078
    public Collection getTimes(Interval interval) {
3079
        if( this.timeSupport!=null ) {
3080
            return this.timeSupport.getTimes(interval);
3081
        }
3082
        return this.provider.getTimes(interval);
3083
    }
3084

    
3085
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3086
        if( this.isEditing() ) {
3087
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
3088
        }
3089
        if( !this.transforms.isEmpty() ) {
3090
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
3091
        }
3092
        FeatureType ft = this.defaultFeatureType;
3093
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3094
        if( attr == null ) {
3095
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
3096
        }
3097
        EditableFeatureType eft = ft.getEditable();
3098
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3099
        if( attr != null ) {
3100
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
3101
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
3102
            }
3103
            eft.remove(attr.getName());
3104
        }
3105
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3106
            timeSupport.getAttributeName(), 
3107
            timeSupport.getDataType()
3108
        );
3109
        attrTime.setIsTime(true);
3110
        attrTime.setFeatureAttributeEmulator(timeSupport);
3111
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3112
        this.defaultFeatureType = eft.getNotEditableCopy();
3113
        
3114
        this.timeSupport = timeSupport;
3115
    }
3116

    
3117
    @Override
3118
    @SuppressWarnings("CloneDoesntCallSuperClone")
3119
    public Object clone() throws CloneNotSupportedException {
3120

    
3121
        DataStoreParameters dsp = getParameters();
3122

    
3123
        DefaultFeatureStore cloned_store = null;
3124

    
3125
        try {
3126
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3127
                openStore(this.getProviderName(), dsp);
3128
            if (transforms != null) {
3129
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3130
                cloned_store.transforms.setStoreForClone(cloned_store);
3131
            }
3132
        } catch (Exception e) {
3133
            throw new CloneException(e);
3134
        }
3135
        return cloned_store;
3136

    
3137
    }
3138

    
3139
    @Override
3140
    public Feature getFeature(DynObject dynobject) {
3141
        if (dynobject instanceof DynObjectFeatureFacade){
3142
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
3143
            return f;
3144
        }
3145
        return null;
3146
    }
3147

    
3148
    @Override
3149
    public Iterator iterator() {
3150
        FeatureSet fset = null;
3151
        try {
3152
            fset  = this.getFeatureSet();
3153
            return fset.fastIterator();
3154
        } catch (DataException ex) {
3155
            throw new RuntimeException(ex);
3156
        } finally {
3157
            DisposeUtils.disposeQuietly(fset);
3158
        }
3159
    }
3160

    
3161
    @Override
3162
    public long size64() {
3163
        FeatureSet fset = null;
3164
        try {
3165
            fset  = this.getFeatureSet();
3166
            return fset.getSize();
3167
        } catch (DataException ex) {
3168
            throw new RuntimeException(ex);
3169
        } finally {
3170
            DisposeUtils.disposeQuietly(fset);
3171
        }
3172
    }
3173
   
3174
    @Override
3175
    public ExpressionBuilder createExpressionBuilder() {
3176
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3177
        return builder;
3178
    }
3179

    
3180
    @Override
3181
    public ExpressionBuilder createExpression() {
3182
        return createExpressionBuilder();
3183
    }
3184

    
3185
    public FeatureSet features() throws DataException {
3186
        // This is to avoid jython to create a property with this name
3187
        // to access method getFeatures.
3188
        return this.getFeatureSet();
3189
    }
3190

    
3191
    @Override
3192
    public DataStoreProviderFactory getProviderFactory() {
3193
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3194
        return factory;
3195
    }
3196

    
3197
    @Override
3198
    public void useCache(String providerName, DynObject parameters) throws DataException {
3199
        throw new UnsupportedOperationException();
3200
    }
3201

    
3202
    @Override
3203
    public boolean isBroken() {
3204
        return this.state.isBroken();
3205
    }
3206

    
3207
    @Override
3208
    public Throwable getBreakingsCause() {
3209
            return this.state.getBreakingsCause();
3210
    }
3211

    
3212
    @Override
3213
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3214
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3215
      if( !factory.supportNumericOID() ) {
3216
          return null;
3217
      }
3218
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3219
      return wrappedIndex;
3220
  }
3221

    
3222
    @Override
3223
    public FeatureReference getFeatureReference(String code) {
3224
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
3225
        return featureReference;
3226
    }
3227

    
3228
    @Override
3229
    public long getPendingChangesCount() {
3230
        if( this.featureManager==null ) {
3231
            return 0;
3232
        }
3233
        return this.featureManager.getPendingChangesCount();
3234
    }
3235

    
3236
    @Override
3237
    public ResourcesStorage getResourcesStorage() {
3238
        ResourcesStorage resourcesStorage;
3239
        try {
3240
            resourcesStorage = this.provider.getResourcesStorage();
3241
            if( resourcesStorage!=null ) {
3242
                return resourcesStorage;
3243
            }
3244
        } catch(Throwable th) {
3245
            
3246
        }
3247
        try {
3248
            DataServerExplorer explorer = this.getExplorer();
3249
            if( explorer==null ) {
3250
                return null;
3251
            }
3252
            resourcesStorage = explorer.getResourcesStorage(this);
3253
            explorer.dispose();
3254
            return resourcesStorage;
3255
        } catch (Exception ex) {
3256
            LOGGER.warn("Can't create resources storage",ex);
3257
            return null;
3258
        }
3259
    }
3260

    
3261
    @Override
3262
    public StoresRepository getStoresRepository() {
3263
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3264
        StoresRepository localRepository = this.provider.getStoresRepository();
3265
        if( localRepository==null ) {
3266
            return mainRepository;
3267
        }
3268
        StoresRepository repository = new BaseStoresRepository(this.getName());
3269
        repository.addRepository(localRepository);
3270
        repository.addRepository(mainRepository);
3271
        return repository;
3272
    }
3273

    
3274
    @Override
3275
    public Feature getSampleFeature() {
3276
            Feature sampleFeature;
3277
            try {
3278
                FeatureSelection theSelection = this.getFeatureSelection();
3279
                if( theSelection!=null && !theSelection.isEmpty() ) {
3280
                    sampleFeature = theSelection.first();
3281
                } else {
3282
                    sampleFeature = this.first();
3283
                }
3284
                if( sampleFeature==null ) {
3285
                    sampleFeature = this.createNewFeature();
3286
                }
3287
            } catch (DataException ex) {
3288
                return null;
3289
            }
3290
            return sampleFeature;
3291
    }
3292

    
3293
    @Override
3294
    public boolean supportReferences() {
3295
        try {
3296
            return this.getDefaultFeatureType().supportReferences();
3297
        } catch (Exception ex) {
3298
            return false;
3299
        }
3300
    }
3301

    
3302
    @Override
3303
    public boolean isTemporary() {
3304
        if( this.provider==null ) {
3305
            return true;
3306
        }
3307
        return this.provider.isTemporary();
3308
    }
3309
    
3310
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3311
        // FIXME this don't work for Store.fType.size() > 1
3312
        FeatureTypeManager manager = this.featureTypeManager;
3313
         if (manager==null) {
3314
             return null;
3315
         }
3316
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3317
         if (originalFeatureType==null) {
3318
             return null;
3319
         }
3320
         return originalFeatureType.getCopy();
3321
    }
3322
}