Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-cvsgis1 / 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 @ 45394

History | View | Annotate | Download (116 KB)

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

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

    
27
import org.gvsig.fmap.dal.feature.impl.editing.memory.SpatialManager;
28
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureTypeManager;
29
import org.gvsig.fmap.dal.feature.impl.editing.memory.FeatureManager;
30

    
31
import java.util.ArrayList;
32
import java.util.Collection;
33
import java.util.Collections;
34
import java.util.HashMap;
35
import java.util.HashSet;
36
import java.util.Iterator;
37
import java.util.List;
38
import java.util.Map;
39
import java.util.Map.Entry;
40
import java.util.Set;
41
import javax.json.JsonObject;
42

    
43
import org.apache.commons.io.FilenameUtils;
44
import org.apache.commons.io.IOUtils;
45
import org.apache.commons.lang3.StringUtils;
46
import org.apache.commons.lang3.mutable.MutableObject;
47
import org.cresques.cts.IProjection;
48
import org.gvsig.expressionevaluator.Expression;
49
import org.gvsig.expressionevaluator.ExpressionBuilder;
50
import org.gvsig.expressionevaluator.ExpressionUtils;
51
import org.gvsig.expressionevaluator.GeometryExpressionUtils;
52
import org.gvsig.fmap.dal.BaseStoresRepository;
53

    
54
import org.gvsig.fmap.dal.DALLocator;
55
import org.gvsig.fmap.dal.DataManager;
56
import org.gvsig.fmap.dal.DataQuery;
57
import org.gvsig.fmap.dal.DataServerExplorer;
58
import org.gvsig.fmap.dal.DataSet;
59
import org.gvsig.fmap.dal.DataStore;
60
import org.gvsig.fmap.dal.DataStoreNotification;
61
import org.gvsig.fmap.dal.DataStoreParameters;
62
import org.gvsig.fmap.dal.DataStoreProviderFactory;
63
import org.gvsig.fmap.dal.StoresRepository;
64
import org.gvsig.fmap.dal.exception.CloneException;
65
import org.gvsig.fmap.dal.exception.CloseException;
66
import org.gvsig.fmap.dal.exception.CreateException;
67
import org.gvsig.fmap.dal.exception.DataException;
68
import org.gvsig.fmap.dal.exception.DataRuntimeException;
69
import org.gvsig.fmap.dal.exception.InitializeException;
70
import org.gvsig.fmap.dal.exception.OpenException;
71
import org.gvsig.fmap.dal.exception.ReadException;
72
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
73
import org.gvsig.fmap.dal.exception.WriteException;
74
import org.gvsig.fmap.dal.feature.EditableFeature;
75
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
76
import org.gvsig.fmap.dal.feature.EditableFeatureType;
77
import org.gvsig.fmap.dal.feature.Feature;
78
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
79
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
80
import org.gvsig.fmap.dal.feature.FeatureCache;
81
import org.gvsig.fmap.dal.feature.FeatureIndex;
82
import org.gvsig.fmap.dal.feature.FeatureIndexes;
83
import org.gvsig.fmap.dal.feature.FeatureLocks;
84
import org.gvsig.fmap.dal.feature.FeatureQuery;
85
import org.gvsig.fmap.dal.feature.FeatureReference;
86
import org.gvsig.fmap.dal.feature.FeatureReferenceSelection;
87
import org.gvsig.fmap.dal.feature.FeatureRules;
88
import org.gvsig.fmap.dal.feature.FeatureSelection;
89
import org.gvsig.fmap.dal.feature.FeatureSet;
90
import org.gvsig.fmap.dal.feature.FeatureSet.DisposableFeatureSetIterable;
91
import org.gvsig.fmap.dal.feature.FeatureStore;
92
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
93
import org.gvsig.fmap.dal.feature.FeatureStoreProviderFactory;
94
import org.gvsig.fmap.dal.feature.FeatureStoreTransforms;
95
import org.gvsig.fmap.dal.feature.FeatureType;
96
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
97
import org.gvsig.fmap.dal.feature.FeatureStoreTimeSupport;
98
import org.gvsig.fmap.dal.feature.FeatureStoreTransform;
99
import org.gvsig.fmap.dal.feature.FeatureType.FeatureTypeChanged;
100
import org.gvsig.fmap.dal.feature.exception.AlreadyEditingException;
101
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
102
import org.gvsig.fmap.dal.feature.exception.CreateFeatureException;
103
import org.gvsig.fmap.dal.feature.exception.DataExportException;
104
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
105
import org.gvsig.fmap.dal.feature.exception.FinishEditingException;
106
import org.gvsig.fmap.dal.feature.exception.GetFeatureTypeException;
107
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureException;
108
import org.gvsig.fmap.dal.feature.exception.IllegalFeatureTypeException;
109
import org.gvsig.fmap.dal.feature.exception.NeedEditingModeException;
110
import org.gvsig.fmap.dal.feature.exception.NoNewFeatureInsertException;
111
import org.gvsig.fmap.dal.feature.exception.NullFeatureTypeException;
112
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
113
import org.gvsig.fmap.dal.feature.exception.PersistenceCantFindFeatureTypeException;
114
import org.gvsig.fmap.dal.feature.exception.PersistenceStoreAlreadyLoadedException;
115
import org.gvsig.fmap.dal.feature.exception.SelectionNotAllowedException;
116
import org.gvsig.fmap.dal.feature.exception.StoreCancelEditingException;
117
import org.gvsig.fmap.dal.feature.exception.StoreDeleteEditableFeatureException;
118
import org.gvsig.fmap.dal.feature.exception.StoreDeleteFeatureException;
119
import org.gvsig.fmap.dal.feature.exception.StoreEditException;
120
import org.gvsig.fmap.dal.feature.exception.StoreInsertFeatureException;
121
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureException;
122
import org.gvsig.fmap.dal.feature.exception.StoreUpdateFeatureTypeException;
123
import org.gvsig.fmap.dal.feature.exception.ValidateFeaturesException;
124
import org.gvsig.fmap.dal.feature.exception.WriteNotAllowedException;
125
import org.gvsig.fmap.dal.feature.impl.featureset.DefaultFeatureSet;
126
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
127
import org.gvsig.fmap.dal.feature.impl.undo.DefaultFeatureCommandsStack;
128
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
129
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
130
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
131
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
132
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
133
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
134
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
135
import org.gvsig.fmap.dal.feature.spi.cache.FeatureCacheProvider;
136
import org.gvsig.fmap.dal.feature.spi.index.FeatureIndexProviderServices;
137
import org.gvsig.fmap.dal.impl.DefaultDataManager;
138
import org.gvsig.fmap.dal.resource.Resource;
139
import org.gvsig.fmap.dal.spi.AbstractDataStore;
140
import org.gvsig.fmap.dal.spi.DataStoreInitializer2;
141
import org.gvsig.fmap.dal.spi.DataStoreProvider;
142
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
143
import org.gvsig.fmap.geom.Geometry;
144
import org.gvsig.fmap.geom.SpatialIndex;
145
import org.gvsig.fmap.geom.primitive.Envelope;
146
import org.gvsig.metadata.MetadataLocator;
147
import org.gvsig.metadata.MetadataManager;
148
import org.gvsig.metadata.exceptions.MetadataException;
149
import org.gvsig.timesupport.Interval;
150
import org.gvsig.tools.ToolsLocator;
151
import org.gvsig.tools.dispose.DisposableIterator;
152
import org.gvsig.tools.dispose.DisposeUtils;
153
import org.gvsig.tools.dynobject.DelegatedDynObject;
154
import org.gvsig.tools.dynobject.DynClass;
155
import org.gvsig.tools.dynobject.DynObject;
156
import org.gvsig.tools.dynobject.DynObjectManager;
157
import org.gvsig.tools.dynobject.DynObject_v2;
158
import org.gvsig.tools.dynobject.DynStruct;
159
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
160
import org.gvsig.tools.dynobject.exception.DynMethodException;
161
import org.gvsig.tools.exception.BaseException;
162
import org.gvsig.tools.exception.NotYetImplemented;
163
import org.gvsig.tools.identitymanagement.SimpleIdentityManager;
164
import org.gvsig.tools.observer.Observable;
165
import org.gvsig.tools.observer.Observer;
166
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
167
import org.gvsig.tools.persistence.PersistenceManager;
168
import org.gvsig.tools.persistence.Persistent;
169
import org.gvsig.tools.persistence.PersistentState;
170
import org.gvsig.tools.persistence.exception.PersistenceException;
171
import org.gvsig.tools.undo.RedoException;
172
import org.gvsig.tools.undo.UndoException;
173
import org.gvsig.tools.undo.command.Command;
174
import org.gvsig.tools.util.HasAFile;
175
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
176
import org.gvsig.tools.util.GetItemWithSize64;
177
import org.gvsig.tools.util.GetItemWithSizeAndIterator64;
178
import org.gvsig.tools.util.PropertiesSupportHelper;
179
import org.gvsig.tools.util.UnmodifiableBasicMap;
180
import org.gvsig.tools.visitor.VisitCanceledException;
181
import org.gvsig.tools.visitor.Visitor;
182

    
183
@SuppressWarnings("UseSpecificCatch")
184
public class DefaultFeatureStore extends AbstractDataStore implements
185
    DataStoreInitializer2, FeatureStoreProviderServices, FeatureStore, Observer {
186

    
187
    private static final String PERSISTENCE_DEFINITION_NAME = "FeatureStore";
188

    
189
    private DataStoreParameters parameters = null;
190
    private FeatureSelection selection;
191
    private FeatureLocks locks;
192

    
193
    private DelegateWeakReferencingObservable delegateObservable =
194
        new DelegateWeakReferencingObservable(this);
195

    
196
    private FeatureCommandsStack commands;
197
    
198
    /*
199
    TODO: Sustituir estos tres manager por un EditingManager
200
    */
201
    private FeatureTypeManager featureTypeManager;
202
    private FeatureManager featureManager;
203
    private SpatialManager spatialManager;
204

    
205
    private FeatureType defaultFeatureType = null;
206
    private List<FeatureType> featureTypes = new ArrayList<>();
207

    
208
    private int mode = MODE_QUERY;
209
    private long versionOfUpdate = 0;
210
    private boolean hasStrongChanges = true;
211
    private boolean hasInserts = true;
212

    
213
    private DefaultDataManager dataManager = null;
214

    
215
    private FeatureStoreProvider provider = null;
216

    
217
    private DefaultFeatureIndexes indexes;
218

    
219
    private DefaultFeatureStoreTransforms transforms;
220

    
221
    /*friend*/ DelegatedDynObject metadata;
222

    
223
    private Set metadataChildren;
224

    
225
    private Long featureCount = null;
226

    
227
    private long temporalOid = 0;
228

    
229
    private FeatureCacheProvider cache;
230

    
231
    private StateInformation state;
232

    
233
    private FeatureStoreTimeSupport timeSupport;
234
    
235
    private PropertiesSupportHelper propertiesSupportHelper;
236

    
237
    private class StateInformation extends HashMap<Object, Object> {
238

    
239
        private static final long serialVersionUID = 4109026189635185666L;
240

    
241
        private boolean broken;
242
        private Throwable breakingsCause;
243

    
244
        @SuppressWarnings("OverridableMethodCallInConstructor")
245
        public StateInformation() {
246
            this.clear();
247
        }
248

    
249
        @Override
250
        public void clear() {
251
            this.broken = false;
252
            this.breakingsCause = null;
253
            super.clear();
254
        }
255

    
256
        public boolean isBroken() {
257
            return this.broken;
258
        }
259

    
260
        public void broken() {
261
            this.broken = true;
262
        }
263

    
264
        public Throwable getBreakingsCause() {
265
            return this.breakingsCause;
266
        }
267

    
268
        public void setBreakingsCause(Throwable cause) {
269
            if( this.breakingsCause==null ) {
270
                this.breakingsCause = cause;
271
            }
272
            this.broken = true;
273
        }
274
    }
275

    
276

    
277

    
278
    /*
279
     * TODO:
280
     *
281
     * - Comprobar que solo se pueden a?adir reglas de validacion sobre un
282
     * EditableFeatureType. - Comprobar que solo se puede hacer un update con un
283
     * featureType al que se le han cambiado las reglas de validacion cuando
284
     * hasStrongChanges=false.
285
     */
286

    
287
    public DefaultFeatureStore() {
288
        this.state = new StateInformation();
289
    }
290
    
291
    @Override
292
    protected DataManager getDataManager() {
293
        return this.dataManager;
294
    }
295

    
296
    @Override
297
    public void intialize(DataManager dataManager,
298
        DataStoreParameters parameters) throws InitializeException {
299

    
300
        DynObjectManager dynManager = ToolsLocator.getDynObjectManager();
301

    
302
        this.metadata = (DelegatedDynObject) dynManager.createDynObject(
303
            FeatureStore.METADATA_DEFINITION_NAME,
304
            MetadataManager.METADATA_NAMESPACE
305
        );
306

    
307
        this.dataManager = (DefaultDataManager) dataManager;
308

    
309
        this.parameters = parameters;
310
        this.transforms = new DefaultFeatureStoreTransforms(this);
311
        try {
312
            indexes = new DefaultFeatureIndexes(this);
313
        } catch (DataException e) {
314
            throw new InitializeException(e);
315
        }
316

    
317
    }
318

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

    
347
    @Override
348
    public DataStoreParameters getParameters() {
349
        if( this.parameters==null ) {
350
            LOGGER.warn("Store parametes are null");
351
        }
352
        return parameters;
353
    }
354

    
355
    public int getMode() {
356
        return this.mode;
357
    }
358

    
359
    @Override
360
    public DataManager getManager() {
361
        return this.dataManager;
362
    }
363

    
364
    @Override
365
    public UnmodifiableBasicMap<String,DataStore> getChildren() {
366
        UnmodifiableBasicMap<String, DataStore> children = this.provider.getChildren();
367
        if( children == null ) {
368
            return UnmodifiableBasicMap.EMPTY_UNMODIFIABLEBASICMAP;
369
        }
370
        return children;
371
    }
372

    
373
    @Override
374
    public FeatureStoreProvider getProvider() {
375
        return this.provider;
376
    }
377

    
378
    public FeatureManager getFeatureManager() {
379
        return this.featureManager;
380
    }
381

    
382
    @Override
383
    public void setFeatureTypes(List types, FeatureType defaultType) {
384
        this.featureTypes = types;
385
        this.defaultFeatureType = defaultType;
386
    }
387

    
388
    public void open() throws OpenException {
389
        if (this.mode != MODE_QUERY) {
390
            // TODO: Se puede hacer un open estando en edicion ?
391
            try {
392
                throw new IllegalStateException();
393
            } catch(Exception ex) {
394
                LOGGER.warn("Opening a store in editing/append mode ("+this.getFullName()+").",ex);
395
            }
396
        }
397
        if( this.notifyChange(DataStoreNotification.BEFORE_OPEN).isCanceled() ) {
398
          return;
399
        }
400
        this.provider.open();
401
        this.notifyChange(DataStoreNotification.AFTER_OPEN);
402
    }
403

    
404
    @Override
405
    public void refresh() throws OpenException, InitializeException {
406
        if (this.mode != MODE_QUERY) {
407
            throw new IllegalStateException();
408
        }
409
        if( this.notifyChange(FeatureStoreNotification.BEFORE_REFRESH).isCanceled() ) {
410
          return;
411
        }
412
        if( state.isBroken() ) {
413
            this.load(state);
414
        } else {
415
            this.featureCount = null;
416
            this.provider.refresh();
417
        }
418
        this.notifyChange(FeatureStoreNotification.AFTER_REFRESH);
419
    }
420

    
421
    public void close() throws CloseException {
422
        if (this.mode != MODE_QUERY) {
423
            // TODO: Se puede hacer un close estando en edicion ?
424
            try {
425
                throw new IllegalStateException();
426
            } catch(Exception ex) {
427
                LOGGER.warn("Clossing a store in editing/append mode ("+this.getFullName()+").",ex);
428
            }
429
        }
430
        if( this.notifyChange(DataStoreNotification.BEFORE_CLOSE).isCanceled() ) {
431
          return;
432
        }
433
        this.featureCount = null;
434
        this.provider.close();
435
        this.notifyChange(DataStoreNotification.AFTER_CLOSE);
436
    }
437

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

    
466
        if (this.featureTypeManager != null) {
467
            this.featureTypeManager.dispose();
468
            this.featureTypeManager = null;
469
        }
470

    
471
        this.featureManager = null;
472
        this.spatialManager = null;
473

    
474
        this.parameters = null;
475
        this.notifyChange(DataStoreNotification.AFTER_DISPOSE);
476
        if (delegateObservable != null) {
477
            this.delegateObservable.deleteObservers();
478
            this.delegateObservable = null;
479
        }
480
    }
481

    
482
    @Override
483
    public boolean allowWrite() {
484
        SimpleIdentityManager identityManager = ToolsLocator.getIdentityManager();
485
        if( ! identityManager.getCurrentIdentity().isAuthorized(DataManager.WRITE_STORE_AUTHORIZATION,this.getParameters(), this.getName()) ) {
486
            return false;
487
        }
488
        return this.provider.allowWrite();
489
    }
490

    
491
    @Override
492
    public boolean canWriteGeometry(int geometryType) throws DataException {
493
        return this.provider.canWriteGeometry(geometryType, 0);
494
    }
495

    
496
    @Override
497
    public DataServerExplorer getExplorer() throws ReadException,
498
        ValidateDataParametersException {
499
        if( this.state.isBroken() ) {
500
            try {
501
                return this.provider.getExplorer();
502
            } catch(Throwable th) {
503
                return null;
504
            }
505
        } else {
506
            return this.provider.getExplorer();
507
        }
508
    }
509

    
510
    /*
511
     * public Metadata getMetadata() throws MetadataNotFoundException {
512
     * // TODO:
513
     * // Si el provider devuelbe null habria que ver de construir aqui
514
     * // los metadatos basicos, como el Envelope y el SRS.
515
     *
516
     * // TODO: Estando en edicion el Envelope deberia de
517
     * // actualizarse usando el spatialManager
518
     * return this.provider.getMetadata();
519
     * }
520
     */
521

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

    
566
    /**
567
     * @throws org.gvsig.fmap.dal.exception.DataException
568
     * @deprecated use getDefaultFeatureType().getDefaultSRS()
569
     */
570
    @Override
571
    public IProjection getSRSDefaultGeometry() throws DataException {
572
        return this.getDefaultFeatureType().getDefaultSRS();
573
    }
574

    
575
    @Override
576
    public FeatureSelection createDefaultFeatureSelection()
577
        throws DataException {
578
        return new DefaultFeatureSelection(this);
579
    }
580

    
581
    @Override
582
    public FeatureProvider createDefaultFeatureProvider(FeatureType type)
583
        throws DataException {
584
        if (type.hasOID()) {
585
            return new DefaultFeatureProvider(type,
586
                this.provider.createNewOID());
587
        }
588
        return new DefaultFeatureProvider(type);
589
    }
590

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

    
626
        }
627

    
628
        if (evaluatedAttr.isEmpty()) {
629
            evaluatedAttr = null;
630
        }
631

    
632
        state.set("evaluatedAttributes", evaluatedAttr);
633
        state.set("defaultFeatureTypeId", defaultFeatureType.getId());
634

    
635
    }
636

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

    
675
    private void load(StateInformation state) {
676
        this.featureTypes = new ArrayList();
677
        this.defaultFeatureType = null;
678
        this.featureCount = null;
679

    
680
        DataStoreParameters params = (DataStoreParameters) state.get("parameters");
681
        try {
682
            intialize(dataManager, params);
683
        } catch(Throwable th) {
684
            state.setBreakingsCause(th);
685
        }
686

    
687
        try {
688
            DataStoreProvider prov = dataManager.createProvider(
689
                getStoreProviderServices(),
690
                params
691
            );
692
            setProvider(prov);
693
        } catch(Throwable th) {
694
            LOGGER.warn("Can't load store from state.", th);
695
            state.setBreakingsCause(th);
696
        }
697
        try {
698
            selection = (FeatureSelection) state.get("selection");
699
        } catch(Throwable th) {
700
            state.setBreakingsCause(th);
701
        }
702

    
703
        try {
704
            this.transforms = (DefaultFeatureStoreTransforms) state.get("transforms");
705
            this.transforms.setFeatureStore(this);
706
            for( FeatureStoreTransform transform : this.transforms ) {
707
                try {
708
                    transform.setUp();
709
                } catch(Throwable th) {
710
                    state.setBreakingsCause(th);
711
                }
712
            }
713
        } catch(Throwable th) {
714
            state.setBreakingsCause(th);
715
        }
716

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

    
748
                    }
749

    
750
            }
751
        } catch(Throwable th) {
752
            state.setBreakingsCause(th);
753
        }
754

    
755

    
756
        try {
757
            String defaultFeatureTypeId = (String) state.get("defaultFeatureTypeId");
758
            FeatureType ftype;
759

    
760
            if (defaultFeatureType == null ||
761
                    defaultFeatureType.getId() == null ||
762
                    !defaultFeatureType.getId().equals(defaultFeatureTypeId)) {
763

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

    
783
        LOGGER.info("load() broken:{}, {}, {}.",
784
                new Object[] { state.isBroken(), this.getProviderName(), params }
785
        );
786
    }
787

    
788
    public DataStoreProviderServices getStoreProviderServices() {
789
        return this;
790
    }
791

    
792
    public static void registerPersistenceDefinition() {
793
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
794
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
795
            DynStruct definition =
796
                manager.addDefinition(DefaultFeatureStore.class,
797
                    PERSISTENCE_DEFINITION_NAME, PERSISTENCE_DEFINITION_NAME
798
                        + " Persistent definition", null, null);
799
            definition.addDynFieldString("dataStoreName").setMandatory(true)
800
                .setPersistent(true);
801

    
802
            definition.addDynFieldObject("parameters")
803
                .setClassOfValue(DynObject.class).setMandatory(true)
804
                .setPersistent(true);
805

    
806
            definition.addDynFieldObject("selection")
807
                .setClassOfValue(FeatureSelection.class).setMandatory(false)
808
                .setPersistent(true);
809

    
810
            definition.addDynFieldObject("transforms")
811
                .setClassOfValue(DefaultFeatureStoreTransforms.class)
812
                .setMandatory(true).setPersistent(true);
813

    
814
            definition.addDynFieldMap("evaluatedAttributes")
815
                .setClassOfItems(List.class) // List<DefaultFeatureAttributeDescriptor>
816
                .setMandatory(false).setPersistent(true);
817

    
818
            definition.addDynFieldString("defaultFeatureTypeId")
819
                .setMandatory(true).setPersistent(true);
820
        }
821
    }
822

    
823
    public static void registerMetadataDefinition() throws MetadataException {
824
        MetadataManager manager = MetadataLocator.getMetadataManager();
825
        if (manager.getDefinition(FeatureStore.METADATA_DEFINITION_NAME) == null) {
826
            DynStruct metadataDefinition =
827
                manager.addDefinition(FeatureStore.METADATA_DEFINITION_NAME, null);
828
            metadataDefinition.extend(manager
829
                .getDefinition(DataStore.METADATA_DEFINITION_NAME));
830
        }
831
    }
832

    
833
    //
834
    // ====================================================================
835
    // Gestion de la seleccion
836
    //
837

    
838
    @Override
839
    public void setSelection(DataSet selection) throws DataException {
840
        this.setSelection((FeatureSet) selection);
841
    }
842

    
843
    @Override
844
    public DataSet createSelection() throws DataException {
845
        return createFeatureSelection();
846
    }
847

    
848
    @Override
849
    public DataSet getSelection() throws DataException {
850
        return this.getFeatureSelection();
851
    }
852

    
853
    @Override
854
    public void setSelection(FeatureSet selection) throws DataException {
855
        setSelection(selection, true);
856
    }
857

    
858
    public void setSelection(FeatureSet selection, boolean undoable)
859
        throws DataException {
860
        if (selection == null) {
861
            if (undoable) {
862
                throw new SelectionNotAllowedException(getName());
863
            }
864

    
865
        } else {
866
            if (selection.equals(this.selection)) {
867
                return;
868
            }
869
            if (!selection.isFromStore(this)) {
870
                throw new SelectionNotAllowedException(getName());
871
            }
872
        }
873

    
874
        if (this.selection != null) {
875
            this.selection.deleteObserver(this);
876
        }
877
        if (selection == null) {
878
            if (this.selection != null) {
879
                this.selection.dispose();
880
            }
881
            this.selection = null;
882
            return;
883
        }
884
        if (selection instanceof FeatureSelection) {
885
            if (undoable && isEditing()) {
886
                commands.selectionSet(this, this.selection,
887
                    (FeatureSelection) selection);
888
            }
889
            if (this.selection != null) {
890
                this.selection.dispose();
891
            }
892
            this.selection = (FeatureSelection) selection;
893
        } else {
894
            if (undoable && isEditing()) {
895
                commands.startComplex("_selectionSet");
896
            }
897
            if (selection instanceof DefaultFeatureSelection) {
898
                DefaultFeatureSelection defSelection =
899
                    (DefaultFeatureSelection) selection;
900
                defSelection.deselectAll(undoable);
901
                defSelection.select(selection, undoable);
902
            } else {
903
                this.selection.deselectAll();
904
                this.selection.select(selection);
905
            }
906
            if (undoable && isEditing()) {
907
                commands.endComplex();
908
            }
909
        }
910
        this.selection.addObserver(this);
911

    
912
        this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
913
    }
914

    
915
    @Override
916
    public FeatureSelection createFeatureSelection() throws DataException {
917
        return this.provider.createFeatureSelection();
918
    }
919

    
920
    @Override
921
    public FeatureSelection getFeatureSelection() throws DataException {
922
        if (selection == null) {
923
            this.selection = createFeatureSelection();
924
            this.selection.addObserver(this);
925
        }
926
        return selection;
927
    }
928

    
929
    //
930
    // ====================================================================
931
    // Gestion de notificaciones
932
    //
933

    
934
    @Override
935
    public FeatureStoreNotification notifyChange(FeatureStoreNotification storeNotification) {
936
        if (delegateObservable != null) {
937
          try {
938
              delegateObservable.notifyObservers(storeNotification);
939
          } catch (Throwable ex) {
940
              LOGGER.warn("Problems notifying changes in the store '"+this.getName()+" ("+storeNotification.getType()+").",ex);
941
          }
942
        }
943
        return storeNotification;
944
    }
945

    
946
    @Override
947
    public FeatureStoreNotification notifyChange(String notification) {
948
      return notifyChange(new DefaultFeatureStoreNotification(this, notification));
949
    }
950
    
951
    public FeatureStoreNotification notifyChange(String notification,
952
      Iterator<FeatureReference> deleteds, 
953
      Iterator<Feature> inserteds, 
954
      Iterator<Feature> updateds, 
955
      Iterator<FeatureTypeChanged> featureTypesChanged, 
956
      boolean isSelectionCompromised) {
957
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
958
            deleteds, inserteds, updateds, featureTypesChanged, isSelectionCompromised));
959
    }
960

    
961
    @Override
962
    public FeatureStoreNotification notifyChange(String notification, FeatureProvider data) {
963
        Feature f = null;
964
        if( data !=null ) {
965
          try {
966
              f = createFeature(data);
967
          } catch (Throwable ex) {
968
              LOGGER.warn("Problems creating a feature to notifying changes in the store '"+this.getName()+" ("+notification+").",ex);
969
          }
970
        }
971
        return notifyChange(notification, f);
972
    }
973

    
974
    public FeatureStoreNotification notifyChange(String notification, Feature feature) {
975
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
976
            feature));
977
    }
978

    
979
    public FeatureStoreNotification notifyChange(String notification, Command command) {
980
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
981
            command));
982
    }
983

    
984
    public FeatureStoreNotification notifyChange(String notification, EditableFeatureType type) {
985
        return notifyChange(new DefaultFeatureStoreNotification(this, notification,
986
            type));
987
    }
988

    
989
    @Override
990
    public FeatureStoreNotification notifyChange(String notification, Resource resource) {
991
        return notifyChange(new DefaultFeatureStoreNotification(this,
992
            DataStoreNotification.RESOURCE_CHANGED));
993
    }
994

    
995
    //
996
    // ====================================================================
997
    // Gestion de bloqueos
998
    //
999

    
1000
    @Override
1001
    public boolean isLocksSupported() {
1002
        return this.provider.isLocksSupported();
1003
    }
1004

    
1005
    @Override
1006
    public FeatureLocks getLocks() throws DataException {
1007
        if (!this.provider.isLocksSupported()) {
1008
            LOGGER.warn("Locks not supported");
1009
            return null;
1010
        }
1011
        if (locks == null) {
1012
            this.locks = this.provider.createFeatureLocks();
1013
        }
1014
        return locks;
1015
    }
1016

    
1017
    //
1018
    // ====================================================================
1019
    // Interface Observable
1020
    //
1021

    
1022
    @Override
1023
    public void disableNotifications() {
1024
        this.delegateObservable.disableNotifications();
1025

    
1026
    }
1027

    
1028
    @Override
1029
    public void enableNotifications() {
1030
        this.delegateObservable.enableNotifications();
1031
    }
1032

    
1033
    @Override
1034
    public void beginComplexNotification() {
1035
        this.delegateObservable.beginComplexNotification();
1036

    
1037
    }
1038

    
1039
    @Override
1040
    public void endComplexNotification() {
1041
        this.delegateObservable.endComplexNotification();
1042

    
1043
    }
1044

    
1045
    @Override
1046
    public void addObserver(Observer observer) {
1047
        if (delegateObservable != null) {
1048
            this.delegateObservable.addObserver(observer);
1049
        }
1050
    }
1051

    
1052
    @Override
1053
    public void deleteObserver(Observer observer) {
1054
        if (delegateObservable != null) {
1055
            this.delegateObservable.deleteObserver(observer);
1056
        }
1057
    }
1058

    
1059
    @Override
1060
    public void deleteObservers() {
1061
        this.delegateObservable.deleteObservers();
1062

    
1063
    }
1064

    
1065
    //
1066
    // ====================================================================
1067
    // Interface Observer
1068
    //
1069
    // Usado para observar:
1070
    // - su seleccion
1071
    // - sus bloqueos
1072
    // - sus recursos
1073
    //
1074

    
1075
    @Override
1076
    public void update(Observable observable, Object notification) {
1077
        if (observable instanceof FeatureSet) {
1078
            if (observable == this.selection) {
1079
                this.notifyChange(DataStoreNotification.SELECTION_CHANGE);
1080
            } else if (observable == this.locks) {
1081
                this.notifyChange(FeatureStoreNotification.LOCKS_CHANGE);
1082
            }
1083

    
1084
        } else if (observable instanceof FeatureStoreProvider) {
1085
            if (observable == this.provider) {
1086

    
1087
            }
1088
        } else if (observable instanceof FeatureReferenceSelection) {
1089
            if(notification instanceof String){
1090
                    this.notifyChange((String)notification);
1091
            }
1092
        }
1093
    }
1094

    
1095
    //
1096
    // ====================================================================
1097
    // Edicion
1098
    //
1099

    
1100
    private void newVersionOfUpdate() {
1101
        this.versionOfUpdate++;
1102
    }
1103

    
1104
    private long currentVersionOfUpdate() {
1105
        return this.versionOfUpdate;
1106
    }
1107

    
1108
    private void checkInEditingMode() throws NeedEditingModeException {
1109
        if (mode != MODE_FULLEDIT) {
1110
            throw new NeedEditingModeException(this.getName());
1111
        }
1112
    }
1113

    
1114
    private void checkNotInAppendMode() throws IllegalStateException {
1115
        if (mode == MODE_APPEND) {
1116
                        throw new IllegalStateException("Error: store "
1117
                                        + this.getFullName() + " is in append mode");
1118
        }
1119
    }
1120

    
1121
    private void checkIsOwnFeature(Feature feature)
1122
        throws IllegalFeatureException {
1123
        if (((DefaultFeature) feature).getStore() != this) {
1124
            throw new IllegalFeatureException(this.getName());
1125
        }
1126
        // FIXME: fixFeatureType no vale para el checkIsOwnFeature
1127
        // fixFeatureType((DefaultFeatureType) feature.getType());
1128
    }
1129

    
1130
    private void exitEditingMode() {
1131
        if (commands != null) {
1132
            commands.clear();
1133
            commands = null;
1134
        }
1135

    
1136
        if (featureTypeManager != null) {
1137
            featureTypeManager.dispose();
1138
            featureTypeManager = null;
1139

    
1140
        }
1141

    
1142
        // TODO implementar un dispose para estos dos
1143
        featureManager = null;
1144
        spatialManager = null;
1145

    
1146
        featureCount = null;
1147

    
1148
        mode = MODE_QUERY;
1149
        hasStrongChanges = true; // Lo deja a true por si las moscas
1150
        hasInserts = true;
1151
    }
1152

    
1153
    @Override
1154
    synchronized public void edit() throws DataException {
1155
        edit(MODE_FULLEDIT);
1156
    }
1157

    
1158
    @Override
1159
    synchronized public void edit(int mode) throws DataException {
1160
        LOGGER.debug("Starting editing in mode: {}", mode);
1161
        try {
1162
            if (this.mode != MODE_QUERY) {
1163
                throw new AlreadyEditingException(this.getName());
1164
            }
1165
            if (!this.provider.supportsAppendMode()) {
1166
                mode = MODE_FULLEDIT;
1167
            }
1168
            switch (mode) {
1169
            case MODE_QUERY:
1170
                throw new IllegalStateException(this.getName());
1171

    
1172
            case MODE_FULLEDIT:
1173
                if (!this.transforms.isEmpty()) {
1174
                    throw new IllegalStateException(this.getName());
1175
                }
1176
                if( notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING).isCanceled() ) {
1177
                  return;
1178
                }
1179
                invalidateIndexes();
1180
                featureManager = new FeatureManager();
1181
                featureTypeManager = new FeatureTypeManager(this);
1182
                spatialManager = new SpatialManager(this, provider.getEnvelope());
1183

    
1184
                commands = new DefaultFeatureCommandsStack(
1185
                        this, featureManager,
1186
                        spatialManager, featureTypeManager);
1187
                this.mode = MODE_FULLEDIT;
1188
                hasStrongChanges = false;
1189
                hasInserts = false;
1190
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1191
                break;
1192
            case MODE_APPEND:
1193
                if (!this.transforms.isEmpty()) {
1194
                    throw new IllegalStateException(this.getName());
1195
                }
1196
                if( notifyChange(FeatureStoreNotification.BEFORE_STARTEDITING).isCanceled() ) {
1197
                  return;
1198
                }
1199
                invalidateIndexes();
1200
                this.provider.beginAppend();
1201
                this.mode = MODE_APPEND;
1202
                hasInserts = false;
1203
                notifyChange(FeatureStoreNotification.AFTER_STARTEDITING);
1204
                break;
1205
            }
1206
        } catch (Exception e) {
1207
            throw new StoreEditException(e, this.getName());
1208
        }
1209
    }
1210

    
1211
    private void invalidateIndexes() {
1212
        setIndexesValidStatus(false);
1213
    }
1214

    
1215
    private void setIndexesValidStatus(boolean valid) {
1216
        FeatureIndexes theIndexes = getIndexes();
1217
        LOGGER.debug("Setting the store indexes to valid status {}: {}", (valid
1218
            ? Boolean.TRUE : Boolean.FALSE), theIndexes);
1219
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1220
            FeatureIndex index = (FeatureIndex) iterator.next();
1221
            if (index instanceof FeatureIndexProviderServices) {
1222
                FeatureIndexProviderServices indexServices =
1223
                    (FeatureIndexProviderServices) index;
1224
                indexServices.setValid(valid);
1225
            }
1226
        }
1227
    }
1228

    
1229
    private void updateIndexes() throws FeatureIndexException {
1230
        FeatureIndexes theIndexes = getIndexes();
1231
        LOGGER.debug("Refilling indexes: {}", theIndexes);
1232
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1233
            FeatureIndex index = (FeatureIndex) iterator.next();
1234
            if (index instanceof FeatureIndexProviderServices) {
1235
                FeatureIndexProviderServices indexServices =
1236
                    (FeatureIndexProviderServices) index;
1237
                indexServices.fill(true, null);
1238
            }
1239
        }
1240
    }
1241

    
1242
    private void waitForIndexes() {
1243
        FeatureIndexes theIndexes = getIndexes();
1244
        LOGGER.debug("Waiting for indexes to finish filling: {}", theIndexes);
1245
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1246
            FeatureIndex index = (FeatureIndex) iterator.next();
1247
            if (index instanceof FeatureIndexProviderServices) {
1248
                FeatureIndexProviderServices indexServices =
1249
                    (FeatureIndexProviderServices) index;
1250
                indexServices.waitForIndex();
1251
            }
1252
        }
1253
    }
1254

    
1255
    private void disposeIndexes() {
1256
        FeatureIndexes theIndexes = getIndexes();
1257
        LOGGER.debug("Disposing indexes: {}", theIndexes);
1258
        if( theIndexes==null ) {
1259
            return;
1260
        }
1261
        for (Iterator iterator = theIndexes.iterator(); iterator.hasNext();) {
1262
            FeatureIndex index = (FeatureIndex) iterator.next();
1263
            if (index instanceof FeatureIndexProviderServices) {
1264
                FeatureIndexProviderServices indexServices =
1265
                    (FeatureIndexProviderServices) index;
1266
                indexServices.dispose();
1267
            }
1268
        }
1269
    }
1270

    
1271
    @Override
1272
    public boolean isEditing() {
1273
        return mode == MODE_FULLEDIT;
1274
    }
1275

    
1276
    @Override
1277
    public boolean isAppending() {
1278
        return mode == MODE_APPEND;
1279
    }
1280

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

    
1333
    @Override
1334
    public void delete(Feature feature) throws DataException {
1335
        this.commands.delete(feature);
1336
    }
1337
    
1338
    @Override
1339
    public void delete(String filter) {
1340
        if( StringUtils.isBlank(filter) ) {
1341
            return;
1342
        }
1343
        this.delete(ExpressionUtils.createExpression(filter));
1344
    }
1345
    
1346
    @Override
1347
    public void delete(Expression filter) {
1348
        // TODO: Optimizar pasandolo directamente al proveedor si no estamos en edicion y lo soporta.
1349
        if( filter == null ) {
1350
            return;
1351
        }
1352
        boolean pendingFinishEditing = false;
1353
        DisposableFeatureSetIterable features = null;
1354
        try {
1355
            if( !this.isEditing() ) {
1356
                pendingFinishEditing = true;
1357
                this.edit();
1358
            }
1359
            FeatureSet fset = this.getFeatureSet(filter);
1360
            features = fset.iterable(); 
1361
            for (Feature f : features) {
1362
                fset.delete(f);
1363
            }
1364
        } catch(DataException ex) {
1365
            throw new DataRuntimeException(ex.getFormatString(), ex.getMessageKey(), ex.getCode()) {};
1366
        } catch(Exception ex) {
1367
            throw new RuntimeException("Can't delete features ("+filter.getPhrase()+").", ex);
1368
        } finally {
1369
            if( pendingFinishEditing ) {
1370
                this.finishEditingQuietly();
1371
            }
1372
            DisposeUtils.disposeQuietly(features);
1373
        }
1374
    }
1375
    
1376
    synchronized public void doDelete(Feature feature) throws DataException {
1377
        try {
1378
            checkInEditingMode();
1379
            checkIsOwnFeature(feature);
1380
            if (feature instanceof EditableFeature) {
1381
                throw new StoreDeleteEditableFeatureException(getName());
1382
            }
1383
            if( notifyChange(FeatureStoreNotification.BEFORE_DELETE, feature).isCanceled() ) {
1384
              return;
1385
            }
1386

    
1387
            //Update the featureManager and the spatialManager
1388
            featureManager.delete(feature.getReference());
1389
            spatialManager.deleteFeature(feature);
1390

    
1391
            newVersionOfUpdate();
1392
            hasStrongChanges = true;
1393
            notifyChange(FeatureStoreNotification.AFTER_DELETE, feature);
1394
        } catch (Exception e) {
1395
            throw new StoreDeleteFeatureException(e, this.getName());
1396
        }
1397
    }
1398

    
1399
    public synchronized void insert(FeatureSet set) throws DataException {
1400
        switch (mode) {
1401
        case MODE_QUERY:
1402
            throw new NeedEditingModeException(this.getName());
1403

    
1404
        case MODE_APPEND:
1405
        case MODE_FULLEDIT:
1406
            break;
1407
        }
1408
        try {
1409
            set.accept((Object obj) -> {
1410
                EditableFeature ef = createNewFeature((Feature) obj);
1411
                insert(ef);
1412
            });
1413
        } catch (BaseException ex) {
1414
            throw new StoreInsertFeatureException(ex, this.getName());
1415
        }
1416
    }
1417
    
1418
    private static EditableFeature lastChangedFeature = null;
1419

    
1420
    @Override
1421
    public synchronized void insert(EditableFeature feature)
1422
        throws DataException {
1423
        LOGGER.debug("In editing mode {}, insert feature: {}", mode, feature);
1424
        try {
1425
            switch (mode) {
1426
            case MODE_QUERY:
1427
                throw new NeedEditingModeException(this.getName());
1428

    
1429
            case MODE_APPEND:
1430
                checkIsOwnFeature(feature);
1431
                if (feature.getSource() != null) {
1432
                    throw new NoNewFeatureInsertException(this.getName());
1433
                }
1434
                if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1435
                  return;
1436
                }
1437
                this.featureCount = null;
1438
                feature.validate(Feature.UPDATE);
1439
                provider.append(((DefaultEditableFeature) feature).getData());
1440
                hasStrongChanges = true;
1441
                hasInserts = true;
1442
                notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1443
                break;
1444

    
1445
            case MODE_FULLEDIT:
1446
                if (feature.getSource() != null) {
1447
                    throw new NoNewFeatureInsertException(this.getName());
1448
                }
1449
                feature.validate(Feature.UPDATE);
1450
                commands.insert(feature);
1451
            }
1452
        } catch (Exception e) {
1453
            throw new StoreInsertFeatureException(e, this.getName());
1454
        }
1455
    }
1456

    
1457
    synchronized public void doInsert(EditableFeature feature)
1458
        throws DataException {
1459
        checkIsOwnFeature(feature);
1460

    
1461
        waitForIndexes();
1462

    
1463
        if( notifyChange(FeatureStoreNotification.BEFORE_INSERT, feature).isCanceled() ) {
1464
          return;
1465
        }
1466
        newVersionOfUpdate();
1467
        if ((lastChangedFeature == null)
1468
            || (lastChangedFeature.getSource() != feature.getSource())) {
1469
            lastChangedFeature = feature;
1470
            feature.validate(Feature.UPDATE);
1471
            lastChangedFeature = null;
1472
        }
1473
        //Update the featureManager and the spatialManager
1474
        ((DefaultEditableFeature) feature).setInserted(true);
1475
        DefaultFeature newFeature = (DefaultFeature) feature.getNotEditableCopy();
1476

    
1477

    
1478
        featureManager.add(newFeature);
1479
        spatialManager.insertFeature(newFeature);
1480

    
1481
        hasStrongChanges = true;
1482
        hasInserts = true;
1483
        notifyChange(FeatureStoreNotification.AFTER_INSERT, feature);
1484
    }
1485

    
1486
    @Override
1487
    public void update(EditableFeature feature)
1488
    throws DataException {
1489
        if (feature.isUpdatable()) {
1490
            commands.update(feature, feature.getSource());
1491
            return;
1492
        }
1493
        // FIXME: Deberiamos lanzar aqui un error en lugar de hacer el insert.
1494
        //        ?O lanzar un mensaje al log?
1495
        insert(feature);
1496
    }
1497

    
1498
    @Override
1499
    public void update(Object... parameters) throws DataException {
1500
        if(parameters.length == 1){
1501
            this.update((EditableFeature)parameters[0]);
1502
            return;
1503
        }
1504
        
1505
        Expression filter = null;
1506
        long end = parameters.length;
1507
        if(parameters.length % 2 == 1){
1508
            Object param = parameters[parameters.length-1];
1509
            if(param != null){
1510
                if(param instanceof Expression){
1511
                    filter = (Expression) param;
1512
                } else {
1513
                    filter = ExpressionUtils.createExpression(param.toString());
1514
                }
1515
            }
1516
        } else {
1517
            end = parameters.length-1;
1518
        }
1519
        
1520
        FeatureSet set = this.getFeatureSet(filter);
1521
        DisposableIterator it = set.fastIterator();
1522
        while (it.hasNext()) {
1523
            Feature feature = (Feature) it.next();
1524
            EditableFeature ef = feature.getEditable();
1525
            for (int i = 0; i < end; i+=2) {
1526
                String name = (String) parameters[i];
1527
                Object value = parameters[i+1];
1528
                ef.set(name, value);
1529
            }
1530
            set.update(ef);
1531
        }
1532
        DisposeUtils.disposeQuietly(it);
1533
        DisposeUtils.disposeQuietly(set);
1534
    }
1535
    
1536
    
1537

    
1538
    synchronized public void doUpdate(EditableFeature feature, Feature oldFeature)
1539
        throws DataException {
1540
        try {
1541
            checkInEditingMode();
1542
            checkIsOwnFeature(feature);
1543
            if( notifyChange(FeatureStoreNotification.BEFORE_UPDATE, feature).isCanceled() ) {
1544
              return;
1545
            }
1546
            newVersionOfUpdate();
1547
            if ((lastChangedFeature == null)
1548
                || (lastChangedFeature.getSource() != feature.getSource())) {
1549
                lastChangedFeature = feature;
1550
                feature.validate(Feature.UPDATE);
1551
                lastChangedFeature = null;
1552
            }
1553

    
1554
            //Update the featureManager and the spatialManager
1555
            Feature newf = feature.getNotEditableCopy();
1556
            featureManager.update(newf, oldFeature);
1557
            spatialManager.updateFeature(newf, oldFeature);
1558

    
1559
            hasStrongChanges = true;
1560
            notifyChange(FeatureStoreNotification.AFTER_UPDATE, feature);
1561
        } catch (Exception e) {
1562
            throw new StoreUpdateFeatureException(e, this.getName());
1563
        }
1564
    }
1565

    
1566
    @Override
1567
    synchronized public void redo() throws RedoException {
1568
        Command redo = commands.getNextRedoCommand();
1569
        try {
1570
            checkInEditingMode();
1571
        } catch (NeedEditingModeException ex) {
1572
            throw new RedoException(redo, ex);
1573
        }
1574
        if( notifyChange(FeatureStoreNotification.BEFORE_REDO, redo).isCanceled() ) {
1575
          return;
1576
        }
1577
        newVersionOfUpdate();
1578
        commands.redo();
1579
        hasStrongChanges = true;
1580
        notifyChange(FeatureStoreNotification.AFTER_REDO, redo);
1581
    }
1582

    
1583
    @Override
1584
    synchronized public void undo() throws UndoException {
1585
        Command undo = commands.getNextUndoCommand();
1586
        try {
1587
            checkInEditingMode();
1588
        } catch (NeedEditingModeException ex) {
1589
            throw new UndoException(undo, ex);
1590
        }
1591
        if( notifyChange(FeatureStoreNotification.BEFORE_UNDO, undo).isCanceled() ) {
1592
          return;
1593
        }
1594
        newVersionOfUpdate();
1595
        commands.undo();
1596
        hasStrongChanges = true;
1597
        notifyChange(FeatureStoreNotification.AFTER_UNDO, undo);
1598
    }
1599

    
1600
    @Override
1601
    public List getRedoInfos() {
1602
        if (isEditing() && (commands != null)) {
1603
            return commands.getRedoInfos();
1604
        } else {
1605
            return null;
1606
        }
1607
    }
1608

    
1609
    @Override
1610
    public List getUndoInfos() {
1611
        if (isEditing() && (commands != null)) {
1612
            return commands.getUndoInfos();
1613
        } else {
1614
            return null;
1615
        }
1616
    }
1617

    
1618
    public synchronized FeatureCommandsStack getCommandsStack()
1619
        throws DataException {
1620
        checkInEditingMode();
1621
        return commands;
1622
    }
1623

    
1624
    @Override
1625
    public boolean cancelEditingQuietly() {
1626
        try {
1627
            this.cancelEditing();
1628
            return true;
1629
        } catch(Exception ex) {
1630
            LOGGER.debug("Can't cancel editing", ex);
1631
            return false;
1632
        }
1633
    }
1634
    
1635
    @Override
1636
    synchronized public void cancelEditing() throws DataException {
1637
        if( spatialManager!=null ) {
1638
            spatialManager.cancelModifies();
1639
        }
1640
        try {
1641
            switch (mode) {
1642
            case MODE_QUERY:
1643
                throw new NeedEditingModeException(this.getName());
1644

    
1645
            case MODE_APPEND:
1646
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1647
                  return;
1648
                }
1649
                provider.abortAppend();
1650
                exitEditingMode();
1651
                ((FeatureSelection) this.getSelection()).deselectAll();
1652
                updateIndexes();
1653
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1654

    
1655
            case MODE_FULLEDIT:
1656
                boolean clearSelection = this.hasStrongChanges;
1657
                if (this.selection instanceof FeatureReferenceSelection) {
1658
                    clearSelection = this.hasInserts;
1659
                }
1660
                if( notifyChange(FeatureStoreNotification.BEFORE_CANCELEDITING).isCanceled() ) {
1661
                  return;
1662
                }
1663
                exitEditingMode();
1664
                if (clearSelection) {
1665
                    ((FeatureSelection) this.getSelection()).deselectAll();
1666
                }
1667
                updateIndexes();
1668
                notifyChange(FeatureStoreNotification.AFTER_CANCELEDITING);   
1669
            }
1670
        } catch (Exception e) {
1671
            throw new StoreCancelEditingException(e, this.getName());
1672
        }
1673
    }
1674

    
1675
    @Override
1676
    public boolean finishEditingQuietly() {
1677
        try {
1678
            this.finishEditing();
1679
            return true;
1680
        } catch(Exception ex) {
1681
            LOGGER.debug("Can't finish editing", ex);
1682
            return false;
1683
        }
1684
    }
1685
    
1686
    @Override
1687
    synchronized public void finishEditing() throws DataException {
1688
        LOGGER.debug("finish editing of mode: {}", mode);
1689
        try {
1690

    
1691
            /*
1692
             * Selection needs to be cleared when editing stops
1693
             * to prevent conflicts with selection remaining from
1694
             * editing mode.
1695
             */
1696
//            ((FeatureSelection) this.getSelection()).deselectAll();
1697
            Map<String,List<FeatureAttributeDescriptor>> computedFields = this.getComputedFields();
1698
            switch (mode) {
1699
            case MODE_QUERY:
1700
                throw new NeedEditingModeException(this.getName());
1701

    
1702
            case MODE_APPEND:
1703
                if( selection!=null ) {
1704
                    selection = null;
1705
                }
1706
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING).isCanceled() ) {
1707
                  return;
1708
                }
1709
                saveDALFile();
1710
                provider.endAppend();
1711
                exitEditingMode();
1712
                this.updateComputedFields(computedFields);
1713
                loadDALFile();
1714
                updateIndexes();
1715
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1716
                break;
1717

    
1718
            case MODE_FULLEDIT:
1719
                if (hasStrongChanges && !this.allowWrite()) {
1720
                    throw new WriteNotAllowedException(getName());
1721
                }
1722
                if( notifyChange(FeatureStoreNotification.BEFORE_FINISHEDITING, 
1723
                        featureManager.getDeleted(),
1724
                        featureManager.getInsertedFeatures(),
1725
                        featureManager.getUpdatedFeatures(),
1726
                        featureTypeManager.getFeatureTypesChanged().iterator(),
1727
                        featureManager.isSelectionCompromised()).isCanceled() ) {
1728
                  return;
1729
                }
1730
                saveDALFile();
1731
                if(featureManager.isSelectionCompromised() && selection!=null ) {
1732
                    selection = null;
1733
                }
1734
                if (hasStrongChanges) {
1735
                    validateFeatures(Feature.FINISH_EDITING);
1736

    
1737
                    /*
1738
                     * This will throw a PerformEditingExceptionif the provider
1739
                     * does not accept the changes (for example, an invalid field name)
1740
                     */
1741
                    provider.performChanges(featureManager.getDeleted(),
1742
                        featureManager.getInserted(),
1743
                        featureManager.getUpdated(),
1744
                        removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1745
                    
1746
                }  
1747
                this.updateComputedFields(computedFields);
1748
                exitEditingMode();
1749
                loadDALFile();
1750
                updateIndexes();
1751
                notifyChange(FeatureStoreNotification.AFTER_FINISHEDITING);
1752
                break;
1753
            }
1754
        } catch (PerformEditingException pee) {
1755
            throw new WriteException(provider.getSourceId().toString(), pee);
1756
        } catch (Exception e) {
1757
            throw new FinishEditingException(e);
1758
        }
1759
    }
1760
    private Map<String,List<FeatureAttributeDescriptor>> getComputedFields() throws DataException {
1761
        Map<String,List<FeatureAttributeDescriptor>> r = new HashMap<>();
1762
        
1763
        List<FeatureType> theTypes = new ArrayList<>();
1764
        theTypes.addAll(this.getFeatureTypes());
1765
        theTypes.add(this.getDefaultFeatureType());
1766
        for( int n=0; n<theTypes.size(); n++ ) {
1767
            FeatureType type = theTypes.get(n);
1768
                for (FeatureAttributeDescriptor attrdesc : type) {
1769
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
1770
                    if( emulator!= null) {
1771
                        List<FeatureAttributeDescriptor> l = r.get(type.getId());
1772
                        if (l==null) {
1773
                            l = new ArrayList<>();
1774
                            r.put(type.getId(), l);
1775
                        }
1776
                        l.add(attrdesc);
1777
                    }
1778
            }
1779
        }
1780
        return r;
1781
    }
1782
    private void updateComputedFields(Map<String,List<FeatureAttributeDescriptor>> computedFields) throws DataException {
1783

    
1784
        List<FeatureType> theTypes = new ArrayList<>();
1785
        theTypes.addAll(this.getFeatureTypes());
1786
        theTypes.add(this.getDefaultFeatureType());
1787
        for( int n=0; n<theTypes.size(); n++ ) {
1788
            DefaultFeatureType type = (DefaultFeatureType) theTypes.get(n);
1789
            List<FeatureAttributeDescriptor> x = computedFields.get(type.getId());
1790
            if(x!=null && !x.isEmpty()) {
1791
                for (FeatureAttributeDescriptor attrdesc : x) {
1792
                    if (type.get(attrdesc.getName())==null) {
1793
                        type.add(attrdesc);
1794
                    }
1795
                }
1796
            }
1797
        }
1798
        
1799
    }
1800
    private List<FeatureTypeChanged> removeCalculatedAttributes(List<FeatureTypeChanged> ftypes) {
1801
        // FIXME: Falta por implementar
1802
//        for (FeatureStoreProvider.FeatureTypeChanged ftype : ftypes) {
1803
//            EditableFeatureType target = (EditableFeatureType) ftype.getTarget();
1804
//            for (FeatureAttributeDescriptor attributeDescriptor : ftype.getSource().getAttributeDescriptors()) {
1805
//                if (attributeDescriptor.isComputed()) {
1806
//                    target.remove(attributeDescriptor.getName());
1807
//                }
1808
//            }
1809
//        }
1810
        return ftypes;
1811
    }
1812
    
1813

    
1814
    private void saveDALFile() {       
1815
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1816
        try {
1817
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1818
            if( resourcesStorage == null || resourcesStorage.isReadOnly() ) {
1819
                return;
1820
            }
1821
            resource = resourcesStorage.getResource("dal");
1822
            if( resource == null || resource.isReadOnly() ) {
1823
                return;
1824
            }
1825
            DALFile dalFile = DALFile.getDALFile();
1826
            dalFile.setStore(this);
1827
            if( !dalFile.isEmpty() ) {
1828
                dalFile.write(resource);
1829
            }
1830
        } catch (Throwable ex) {
1831
            LOGGER.warn("Can't save DAL resource", ex);
1832
        } finally {
1833
            IOUtils.closeQuietly(resource);
1834
        }
1835
    }
1836
    
1837
    private void loadDALFile() {
1838
        org.gvsig.tools.resourcesstorage.ResourcesStorage.Resource resource = null;
1839
        try {
1840
            ResourcesStorage resourcesStorage = this.getResourcesStorage();
1841
            if( resourcesStorage == null ) {
1842
                return;
1843
            }
1844
            resource = resourcesStorage.getResource("dal");
1845
            if( resource == null || !resource.exists() ) {
1846
                return;
1847
            }
1848
            DALFile dalFile = DALFile.getDALFile(resource);
1849
            if( !dalFile.isEmpty() ) {
1850
                dalFile.updateStore(this);
1851
            }
1852
        } catch (Throwable ex) {
1853
            LOGGER.warn("Can't load DAL resource", ex);
1854
        } finally {
1855
            IOUtils.closeQuietly(resource);
1856
        }
1857
    }
1858
    
1859
    /**
1860
     * Save changes in the provider without leaving the edit mode.
1861
     * Do not call observers to communicate a change of ediding mode.
1862
     * The operation's history is eliminated to prevent inconsistencies
1863
     * in the data.
1864
     *
1865
     * @throws DataException
1866
     */
1867
    @Override
1868
    synchronized public void commitChanges() throws DataException {
1869
      LOGGER.debug("commitChanges of mode: {}", mode);
1870
      if( !canCommitChanges() ) {
1871
              throw new WriteNotAllowedException(getName());
1872
      }
1873
      try {
1874
        switch (mode) {
1875
        case MODE_QUERY:
1876
          throw new NeedEditingModeException(this.getName());
1877

    
1878
        case MODE_APPEND:
1879
          this.provider.endAppend();
1880
          exitEditingMode();
1881
          invalidateIndexes();
1882
          this.provider.beginAppend();
1883
          hasInserts = false;
1884
          break;
1885

    
1886
        case MODE_FULLEDIT:
1887
          if (hasStrongChanges && !this.allowWrite()) {
1888
            throw new WriteNotAllowedException(getName());
1889
          }
1890
          if (hasStrongChanges) {
1891
            validateFeatures(Feature.FINISH_EDITING);
1892
            provider.performChanges(featureManager.getDeleted(),
1893
              featureManager.getInserted(),
1894
              featureManager.getUpdated(),
1895
              removeCalculatedAttributes(featureTypeManager.getFeatureTypesChanged()).iterator());
1896
          }
1897
          invalidateIndexes();
1898
          featureManager = new FeatureManager();
1899
          featureTypeManager = new FeatureTypeManager(this);
1900
          spatialManager = new SpatialManager(this, provider.getEnvelope());
1901

    
1902
          commands =
1903
            new DefaultFeatureCommandsStack(this, featureManager,
1904
              spatialManager, featureTypeManager);
1905
          featureCount = null;
1906
          hasStrongChanges = false;
1907
          hasInserts = false;
1908
          break;
1909
        }
1910
      } catch (Exception e) {
1911
        throw new FinishEditingException(e);
1912
      }
1913
    }
1914

    
1915
    @Override
1916
    synchronized public boolean canCommitChanges() throws DataException {
1917
        if ( !this.allowWrite()) {
1918
                return false;
1919
        }
1920
            switch (mode) {
1921
            default:
1922
        case MODE_QUERY:
1923
                return false;
1924

    
1925
        case MODE_APPEND:
1926
                return true;
1927

    
1928
        case MODE_FULLEDIT:
1929
            List types = this.getFeatureTypes();
1930
            for( int i=0; i<types.size(); i++ ) {
1931
                    Object type = types.get(i);
1932
                    if( type instanceof DefaultEditableFeatureType ) {
1933
                            if( ((DefaultEditableFeatureType)type).hasStrongChanges() ) {
1934
                                    return false;
1935
                            }
1936
                    }
1937
            }
1938
            return true;
1939
            }
1940
    }
1941

    
1942
    @Override
1943
    public void beginEditingGroup(String description)
1944
        throws NeedEditingModeException {
1945
        checkInEditingMode();
1946
        commands.startComplex(description);
1947
    }
1948

    
1949
    @Override
1950
    public void endEditingGroup() throws NeedEditingModeException {
1951
        checkInEditingMode();
1952
        commands.endComplex();
1953
    }
1954

    
1955
    @Override
1956
    public boolean isAppendModeSupported() {
1957
        return this.provider.supportsAppendMode();
1958
    }
1959

    
1960
    @Override
1961
    public void export(DataServerExplorer explorer, String provider,
1962
        NewFeatureStoreParameters params) throws DataException {
1963

    
1964
        if (this.getFeatureTypes().size() != 1) {
1965
            throw new NotYetImplemented(
1966
                "export whith more than one type not yet implemented");
1967
        }
1968
        FeatureSelection featureSelection = (FeatureSelection) getSelection();
1969
        FeatureStore target = null;
1970
        FeatureSet features = null;
1971
        DisposableIterator iterator = null;
1972
        try {
1973
            FeatureType type = this.getDefaultFeatureType();
1974
            if ((params.getDefaultFeatureType() == null)
1975
                || (params.getDefaultFeatureType().size() == 0)) {
1976
                params.setDefaultFeatureType(type.getEditable());
1977

    
1978
            }
1979
            explorer.add(provider, params, true);
1980

    
1981
            DataManager manager = DALLocator.getDataManager();
1982
            target = (FeatureStore) manager.openStore(provider, params);
1983
            FeatureType targetType = target.getDefaultFeatureType();
1984

    
1985
            target.edit(MODE_APPEND);
1986
            FeatureAttributeDescriptor[] pkattrs = type.getPrimaryKey();
1987
            if (featureSelection.getSize() > 0) {
1988
                features = this.getFeatureSelection();
1989
            } else {
1990
                if ((pkattrs != null) && (pkattrs.length > 0)) {
1991
                    FeatureQuery query = createFeatureQuery();
1992
                    for (FeatureAttributeDescriptor pkattr : pkattrs) {
1993
                        query.getOrder().add(pkattr.getName(), true);
1994
                    }
1995
                    features = this.getFeatureSet(query);
1996
                } else {
1997
                    features = this.getFeatureSet();
1998
                }
1999
            }
2000
            iterator = features.fastIterator();
2001
            while (iterator.hasNext()) {
2002
                DefaultFeature feature = (DefaultFeature) iterator.next();
2003
                target.insert(target.createNewFeature(targetType, feature));
2004
            }
2005
            target.finishEditing();
2006
            target.dispose();
2007
        } catch (Exception e) {
2008
            throw new DataExportException(e, params.toString());
2009
        } finally {
2010
            dispose(iterator);
2011
            dispose(features);
2012
            dispose(target);
2013
        }
2014
    }
2015

    
2016
    public void copyTo(final FeatureStore target) {
2017
        boolean finishEditingAtEnd = false;
2018
        try {
2019
            if( !target.isEditing() && !target.isAppending() ) {
2020
                finishEditingAtEnd = true;
2021
                target.edit(MODE_APPEND);
2022
            }
2023
            this.accept(new Visitor() {
2024
                @Override
2025
                public void visit(Object obj) throws VisitCanceledException, BaseException {
2026
                    Feature f_src = (Feature) obj;
2027
                    EditableFeature f_dst = target.createNewFeature(f_src);
2028
                    target.insert(f_dst);
2029
                }
2030
            });
2031
            if( finishEditingAtEnd ) {
2032
                target.finishEditing();
2033
            }
2034
            
2035
        } catch(Exception ex) {
2036
            try {
2037
                if( finishEditingAtEnd ) {
2038
                    target.cancelEditing();
2039
                }
2040
            } catch (Exception ex1) {
2041
            }
2042
            throw new RuntimeException("Can't copy store.",ex);
2043
        }
2044
            
2045
    }
2046
    
2047
    //
2048
    // ====================================================================
2049
    // Obtencion de datos
2050
    // getDataCollection, getFeatureCollection
2051
    //
2052

    
2053
    @Override
2054
    public DataSet getDataSet() throws DataException {
2055
        checkNotInAppendMode();
2056
        FeatureQuery query =
2057
            new DefaultFeatureQuery(this.getDefaultFeatureType());
2058
        return new DefaultFeatureSet(this, query);
2059
    }
2060

    
2061
    @Override
2062
    public DataSet getDataSet(DataQuery dataQuery) throws DataException {
2063
        checkNotInAppendMode();
2064
        return new DefaultFeatureSet(this, (FeatureQuery) dataQuery);
2065
    }
2066

    
2067
    @Override
2068
    public void getDataSet(Observer observer) throws DataException {
2069
        checkNotInAppendMode();
2070
        this.getFeatureSet(null, observer);
2071
    }
2072

    
2073
    @Override
2074
    public void getDataSet(DataQuery dataQuery, Observer observer)
2075
        throws DataException {
2076
        checkNotInAppendMode();
2077
        this.getFeatureSet((FeatureQuery) dataQuery, observer);
2078
    }
2079

    
2080
    @Override
2081
    public FeatureSet getFeatureSet() throws DataException {
2082
        return this.getFeatureSet((FeatureQuery)null);
2083
    }
2084

    
2085
    @Override
2086
    public FeatureSet getFeatureSet(FeatureQuery featureQuery)
2087
        throws DataException {
2088
        checkNotInAppendMode();
2089
        if( featureQuery==null ) {
2090
            featureQuery = new DefaultFeatureQuery(this.getDefaultFeatureType());
2091
        }
2092
        return new DefaultFeatureSet(this, featureQuery);
2093
    }
2094

    
2095
    @Override
2096
    public FeatureSet getFeatureSet(String filter) throws DataException {
2097
        return this.getFeatureSet(filter, null, true);
2098
    }
2099

    
2100
    @Override
2101
    public FeatureSet getFeatureSet(String filter, String sortBy) throws DataException {
2102
        return this.getFeatureSet(filter, sortBy, true);
2103
    }
2104

    
2105
    @Override
2106
    public FeatureSet getFeatureSet(Expression filter) throws DataException {
2107
        return this.getFeatureSet(filter, null, true);
2108
    }
2109
    
2110
    @Override
2111
    public FeatureSet getFeatureSet(Expression filter, String sortBy) throws DataException {
2112
        return this.getFeatureSet(filter, sortBy, true);
2113
    }
2114

    
2115
    @Override
2116
    public FeatureSet getFeatureSet(Expression filter, String sortBy, boolean asc) throws DataException {
2117
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2118
        return this.getFeatureSet(query);
2119
    }
2120
    
2121
    @Override
2122
    public FeatureSet getFeatureSet(String filter, String sortBy, boolean asc) throws DataException {
2123
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2124
        return this.getFeatureSet(query);
2125
    }
2126
    
2127
    @Override
2128
    public List<Feature> getFeatures(String filter)  {
2129
        return this.getFeatures(filter, null, true);
2130
    }
2131

    
2132
    @Override
2133
    public List<Feature> getFeatures(String filter, String sortBy)  {
2134
        return this.getFeatures(filter, sortBy, true);
2135
    }
2136

    
2137
    @Override
2138
    public List<Feature> getFeatures(String filter, String sortBy, boolean asc)  {
2139
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2140
        return this.getFeatures(query, 0);
2141
    }
2142
    
2143
    @Override
2144
    public List<Feature> getFeatures(Expression filter)  {
2145
        return this.getFeatures(filter, null, true);
2146
    }
2147

    
2148
    @Override
2149
    public List<Feature> getFeatures(Expression filter, String sortBy)  {
2150
        return this.getFeatures(filter, sortBy, true);
2151
    }
2152

    
2153
    @Override
2154
    public List<Feature> getFeatures(Expression filter, String sortBy, boolean asc)  {
2155
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2156
        return this.getFeatures(query, 0);
2157
    }
2158
    
2159
    @Override
2160
    public List<Feature> getFeatures(FeatureQuery query)  {
2161
        return this.getFeatures(query, 0);
2162
    }
2163
    
2164
    @Override
2165
    public List<Feature> getFeatures(FeatureQuery query, int pageSize)  {
2166
        try {
2167
            if( pageSize<=0 ) {
2168
                pageSize = 100;
2169
            }
2170
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2171
            return pager.asList();
2172
        } catch (BaseException ex) {
2173
            throw new RuntimeException("Can't create the list of features.", ex);
2174
        }
2175
    }
2176

    
2177
    @Override
2178
    public List<Feature> getFeatures() {
2179
        return this.getFeatures(null, 0);
2180
    }
2181

    
2182
    @Override
2183
    public GetItemWithSizeAndIterator64<Feature> getFeatures64() {
2184
        return this.getFeatures64(null, 0);
2185
    }
2186

    
2187
    @Override
2188
    public GetItemWithSizeAndIterator64<Feature> getFeatures64(String filter) {
2189
        return this.getFeatures64(filter, null, true);
2190
    }
2191
    
2192
    @Override
2193
    public GetItemWithSizeAndIterator64<Feature> getFeatures64(String filter, String sortBy, boolean asc)  {
2194
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2195
        return this.getFeatures64(query, 0);
2196
    }
2197

    
2198
    @Override
2199
    public GetItemWithSizeAndIterator64<Feature> getFeatures64(FeatureQuery query, int pageSize)  {
2200
        try {
2201
            if( pageSize<=0 ) {
2202
                pageSize = 100;
2203
            }
2204
            FeaturePagingHelper pager = this.dataManager.createFeaturePagingHelper(this, query, pageSize);
2205
            return pager;
2206
        } catch (BaseException ex) {
2207
            throw new RuntimeException("Can't create the list of features.", ex);
2208
        }
2209
    }
2210

    
2211
    @Override
2212
    public Feature first() throws DataException {
2213
        return this.findFirst((FeatureQuery)null);
2214
    }
2215
    
2216
    @Override
2217
    public Feature findFirst(String filter) throws DataException {
2218
        return this.findFirst(filter, null, true);
2219
    }
2220

    
2221
    @Override
2222
    public Feature findFirst(String filter, String sortBy) throws DataException {
2223
        return this.findFirst(filter, sortBy, true);
2224
    }
2225

    
2226
    @Override
2227
    public Feature findFirst(String filter, String sortBy, boolean asc) throws DataException {
2228
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2229
        return findFirst(query);
2230
    }
2231
    
2232
    @Override
2233
    public Feature findFirst(Expression filter) throws DataException {
2234
        return this.findFirst(filter, null, true);
2235
    }
2236

    
2237
    @Override
2238
    public Feature findFirst(Expression filter, String sortBy) throws DataException {
2239
        return this.findFirst(filter, sortBy, true);
2240
    }
2241

    
2242
    @Override
2243
    public Feature findFirst(Expression filter, String sortBy, boolean asc) throws DataException {
2244
        FeatureQuery query = this.createFeatureQuery(filter, sortBy, asc);
2245
        return findFirst(query);
2246
    }
2247
    
2248
    @Override
2249
    public Feature findFirst(FeatureQuery query) throws DataException {
2250
        if( query == null ) {
2251
            query = this.createFeatureQuery();
2252
        } else {
2253
            query = query.getCopy();
2254
        }
2255
        query.setLimit(1);
2256
        final MutableObject<Feature> feature = new MutableObject<>();
2257
        try {
2258
            this.accept(new Visitor() {
2259
                @Override
2260
                public void visit(Object obj) throws VisitCanceledException, BaseException {
2261
                    feature.setValue((Feature) obj);
2262
                    throw new VisitCanceledException();
2263
                }
2264
            }, query);
2265
        } catch(VisitCanceledException ex) {
2266

    
2267
        } catch(DataException ex) {
2268
            throw ex;
2269
        } catch(Exception ex) {
2270
            throw new RuntimeException("", ex);
2271
        }
2272
        return feature.getValue();
2273
    }
2274

    
2275
    @Override
2276
    public void accept(Visitor visitor) throws BaseException {
2277
        this.accept(visitor, null);
2278
    }
2279

    
2280
    @Override
2281
    public void accept(Visitor visitor, DataQuery dataQuery)
2282
        throws BaseException {
2283
        FeatureSet set = getFeatureSet((FeatureQuery) dataQuery);
2284
        try {
2285
            set.accept(visitor);
2286
        } finally {
2287
            set.dispose();
2288
        }
2289
    }
2290

    
2291
    public FeatureType getFeatureType(FeatureQuery featureQuery)
2292
        throws DataException {
2293
        DefaultFeatureType fType =
2294
            (DefaultFeatureType) this.getFeatureType(featureQuery
2295
                .getFeatureTypeId());
2296
        if( featureQuery.hasAttributeNames() || 
2297
            featureQuery.hasConstantsAttributeNames() ||
2298
            fType.hasRequiredFields()    
2299
            ) {
2300
            if( featureQuery.hasGroupByColumns()) {
2301
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames(), false );
2302
            } else {
2303
                return fType.getSubtype(featureQuery.getAttributeNames(), featureQuery.getConstantsAttributeNames());
2304
            }
2305
        }
2306
        return fType;
2307
    }
2308

    
2309
    @Override
2310
    public void getFeatureSet(Observer observer) throws DataException {
2311
        checkNotInAppendMode();
2312
        this.getFeatureSet(null, observer);
2313
    }
2314

    
2315
    @Override
2316
    public void getFeatureSet(FeatureQuery query, Observer observer)
2317
        throws DataException {
2318
        class LoadInBackGround implements Runnable {
2319

    
2320
            private final FeatureStore store;
2321
            private final FeatureQuery query;
2322
            private final Observer observer;
2323

    
2324
            public LoadInBackGround(FeatureStore store, FeatureQuery query,
2325
                Observer observer) {
2326
                this.store = store;
2327
                this.query = query;
2328
                this.observer = observer;
2329
            }
2330

    
2331
            void notify(FeatureStoreNotification theNotification) {
2332
                observer.update(store, theNotification);
2333
            }
2334

    
2335
            @Override
2336
            public void run() {
2337
                FeatureSet set = null;
2338
                try {
2339
                    set = store.getFeatureSet(query);
2340
                    notify(new DefaultFeatureStoreNotification(store,
2341
                        FeatureStoreNotification.LOAD_FINISHED, set));
2342
                } catch (Exception e) {
2343
                    notify(new DefaultFeatureStoreNotification(store,
2344
                        FeatureStoreNotification.LOAD_FINISHED, e));
2345
                } finally {
2346
                    dispose(set);
2347
                }
2348
            }
2349
        }
2350

    
2351
        checkNotInAppendMode();
2352
        if (query == null) {
2353
            query = new DefaultFeatureQuery(this.getDefaultFeatureType());
2354
        }
2355
        LoadInBackGround task = new LoadInBackGround(this, query, observer);
2356
        Thread thread = new Thread(task, "Load Feature Set in background");
2357
        thread.start();
2358
    }
2359

    
2360
    @Override
2361
    public Feature getFeatureByReference(FeatureReference reference)
2362
        throws DataException {
2363
        checkNotInAppendMode();
2364
        DefaultFeatureReference ref = (DefaultFeatureReference) reference;
2365
        FeatureType featureType;
2366
        if (ref.getFeatureTypeId() == null) {
2367
            featureType = this.getDefaultFeatureType();
2368
        } else {
2369
            featureType = this.getFeatureType(ref.getFeatureTypeId());
2370
        }
2371
        return this.getFeatureByReference(reference, featureType);
2372
    }
2373

    
2374
    @Override
2375
    public Feature getFeatureByReference(FeatureReference reference,
2376
        FeatureType featureType) throws DataException {
2377
        checkNotInAppendMode();
2378
        featureType = fixFeatureType((DefaultFeatureType) featureType);
2379
        if (this.mode == MODE_FULLEDIT) {
2380
            Feature f = featureManager.get(reference, this, featureType);
2381
            if (f != null) {
2382
                return f;
2383
            }
2384
        }
2385

    
2386
        FeatureType sourceFeatureType = featureType;
2387
        if (!this.transforms.isEmpty()) {
2388
            sourceFeatureType = this.transforms.getSourceFeatureTypeFrom(featureType);
2389
        }
2390
        // TODO comprobar que el id es de este store
2391

    
2392
        DefaultFeature feature =
2393
            new DefaultFeature(this,
2394
                this.provider.getFeatureProviderByReference(
2395
                    (FeatureReferenceProviderServices) reference, sourceFeatureType));
2396

    
2397
        if (!this.transforms.isEmpty()) {
2398
            return this.transforms.applyTransform(feature, featureType);
2399
        }
2400
        return feature;
2401
    }
2402

    
2403
    //
2404
    // ====================================================================
2405
    // Gestion de features
2406
    //
2407

    
2408
    private FeatureType fixFeatureType(DefaultFeatureType type)
2409
        throws DataException {
2410
        FeatureType original = this.getDefaultFeatureType();
2411

    
2412
        if ((type == null) || type.equals(original)) {
2413
            return original;
2414
        } else {
2415
            if (!type.isSubtypeOf(original)) {
2416
                Iterator iter = this.getFeatureTypes().iterator();
2417
                FeatureType tmpType;
2418
                boolean found = false;
2419
                while (iter.hasNext()) {
2420
                    tmpType = (FeatureType) iter.next();
2421
                    if (type.equals(tmpType)) {
2422
                        return type;
2423

    
2424
                    } else
2425
                        if (type.isSubtypeOf(tmpType)) {
2426
                            found = true;
2427
                            original = tmpType;
2428
                            break;
2429
                        }
2430

    
2431
                }
2432
                if (!found) {
2433
                    throw new IllegalFeatureTypeException(getName());
2434
                }
2435
            }
2436
        }
2437

    
2438
        // Checks that type has all fields of pk
2439
        // else add the missing attributes at the end.
2440
        if (!original.hasOID()) {
2441
            // Gets original pk attributes
2442
            DefaultEditableFeatureType edOriginal =
2443
                (DefaultEditableFeatureType) original.getEditable();
2444
            FeatureAttributeDescriptor orgAttr;
2445
            Iterator edOriginalIter = edOriginal.iterator();
2446
            while (edOriginalIter.hasNext()) {
2447
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2448
                if (!orgAttr.isPrimaryKey()) {
2449
                    edOriginalIter.remove();
2450
                }
2451
            }
2452

    
2453
            // Checks if all pk attributes are in type
2454
            Iterator typeIterator;
2455
            edOriginalIter = edOriginal.iterator();
2456
            FeatureAttributeDescriptor attr;
2457
            while (edOriginalIter.hasNext()) {
2458
                orgAttr = (FeatureAttributeDescriptor) edOriginalIter.next();
2459
                typeIterator = type.iterator();
2460
                while (typeIterator.hasNext()) {
2461
                    attr = (FeatureAttributeDescriptor) typeIterator.next();
2462
                    if (attr.getName().equals(orgAttr.getName())) {
2463
                        edOriginalIter.remove();
2464
                        break;
2465
                    }
2466
                }
2467
            }
2468

    
2469
            // add missing pk attributes if any
2470
            if (edOriginal.size() > 0) {
2471
                boolean isEditable = type instanceof DefaultEditableFeatureType;
2472
                DefaultEditableFeatureType edType =
2473
                    (DefaultEditableFeatureType) original.getEditable();
2474
                edType.clear();
2475
                edType.addAll(type);
2476
                edType.addAll(edOriginal);
2477
                if (!isEditable) {
2478
                    type = (DefaultFeatureType) edType.getNotEditableCopy();
2479
                }
2480
            }
2481

    
2482
        }
2483

    
2484
        return type;
2485
    }
2486

    
2487
    @Override
2488
    public void validateFeatures(int mode) throws DataException {
2489
        FeatureSet collection = null;
2490
        DisposableIterator iter = null;
2491
        try {
2492
            FeatureRules rules = this.getDefaultFeatureType().getRules();
2493
            if( rules==null || rules.isEmpty() ) {
2494
                return;
2495
            }
2496
            checkNotInAppendMode();
2497
            collection = this.getFeatureSet();
2498
            iter = collection.fastIterator();
2499
            long previousVersionOfUpdate = currentVersionOfUpdate();
2500
            while (iter.hasNext()) {
2501
                ((DefaultFeature) iter.next()).validate(mode);
2502
                if (previousVersionOfUpdate != currentVersionOfUpdate()) {
2503
                    throw new ConcurrentDataModificationException(getName());
2504
                }
2505
            }
2506
        } catch (Exception e) {
2507
            throw new ValidateFeaturesException(e, getName());
2508
        } finally {
2509
            DisposeUtils.disposeQuietly(iter);
2510
            DisposeUtils.disposeQuietly(collection);
2511
        }
2512
    }
2513

    
2514
    @Override
2515
    public FeatureType getDefaultFeatureType() throws DataException {
2516
        try {
2517

    
2518
            if (isEditing()) {
2519
                FeatureType auxFeatureType =
2520
                    featureTypeManager.getType(defaultFeatureType.getId());
2521
                if (auxFeatureType != null) {
2522
                    return avoidEditable(auxFeatureType);
2523
                }
2524
            }
2525
            FeatureType type = this.transforms.getDefaultFeatureType();
2526
                if (type != null) {
2527
                return avoidEditable(type);
2528
                }
2529

    
2530
            return avoidEditable(defaultFeatureType);
2531

    
2532
        } catch (Exception e) {
2533
            throw new GetFeatureTypeException(e, getName());
2534
        }
2535
    }
2536

    
2537
    @Override
2538
    public FeatureType getDefaultFeatureTypeQuietly() {
2539
      try {
2540
        return this.getDefaultFeatureType();
2541
      } catch(Exception ex) {
2542
        return null;
2543
      }
2544
    }
2545
    
2546
    private FeatureType avoidEditable(FeatureType ft) {
2547
        if (ft instanceof EditableFeatureType) {
2548
            return ((EditableFeatureType) ft).getNotEditableCopy();
2549
        } else {
2550
            return ft;
2551
        }
2552
    }
2553

    
2554
    @Override
2555
    public FeatureType getFeatureType(String featureTypeId)
2556
        throws DataException {
2557
        if (featureTypeId == null) {
2558
            return this.getDefaultFeatureType();
2559
        }
2560
        try {
2561
            if (isEditing()) {
2562
                FeatureType auxFeatureType =
2563
                    featureTypeManager.getType(featureTypeId);
2564
                if (auxFeatureType != null) {
2565
                    return auxFeatureType;
2566
                }
2567
            }
2568
            FeatureType type = this.transforms.getFeatureType(featureTypeId);
2569
            if (type != null) {
2570
                return type;
2571
            }
2572
            Iterator iter = this.featureTypes.iterator();
2573
            while (iter.hasNext()) {
2574
                type = (FeatureType) iter.next();
2575
                if (type.getId().equals(featureTypeId)) {
2576
                    return type;
2577
                }
2578
            }
2579
            return null;
2580
        } catch (Exception e) {
2581
            throw new GetFeatureTypeException(e, getName());
2582
        }
2583
    }
2584

    
2585
    public FeatureType getProviderDefaultFeatureType() {
2586
        return defaultFeatureType;
2587
    }
2588

    
2589
    @Override
2590
    public List getFeatureTypes() throws DataException {
2591
        try {
2592
            List types;
2593
            if (isEditing()) {
2594
                types = new ArrayList();
2595
                Iterator it = featureTypes.iterator();
2596
                while (it.hasNext()) {
2597
                    FeatureType type = (FeatureType) it.next();
2598
                    FeatureType typeaux =
2599
                        featureTypeManager.getType(type.getId());
2600
                    if (typeaux != null) {
2601
                        types.add(typeaux);
2602
                    } else {
2603
                        types.add(type);
2604
                    }
2605
                }
2606
                it = featureTypeManager.newsIterator();
2607
                while (it.hasNext()) {
2608
                    FeatureType type = (FeatureType) it.next();
2609
                    types.add(type);
2610
                }
2611
            } else {
2612
                types = this.transforms.getFeatureTypes();
2613
                if (types == null) {
2614
                    types = featureTypes;
2615
                }
2616
            }
2617
            return Collections.unmodifiableList(types);
2618
        } catch (Exception e) {
2619
            throw new GetFeatureTypeException(e, getName());
2620
        }
2621
    }
2622

    
2623
    public List getProviderFeatureTypes() throws DataException {
2624
        return Collections.unmodifiableList(this.featureTypes);
2625
    }
2626

    
2627
    @Override
2628
    public Feature createFeature(FeatureProvider data) throws DataException {
2629
        DefaultFeature feature = new DefaultFeature(this, data);
2630
        return feature;
2631
    }
2632

    
2633
    public Feature createFeature(FeatureProvider data, FeatureType type)
2634
        throws DataException {
2635
        // FIXME: falta por implementar
2636
        // Comprobar si es un subtipo del feature de data
2637
        // y construir un feature usando el subtipo.
2638
        // Probablemente requiera generar una copia del data.
2639
        throw new NotYetImplemented();
2640
    }
2641

    
2642
    @Override
2643
    public EditableFeature createNewFeature(FeatureType type,
2644
        Feature defaultValues) throws DataException {
2645
        try {
2646
            FeatureProvider data = createNewFeatureProvider(type);
2647
            DefaultEditableFeature feature =
2648
                new DefaultEditableFeature(this, data);
2649
            feature.initializeValues(defaultValues);
2650
            data.setNew(true);
2651

    
2652
            return feature;
2653
        } catch (Exception e) {
2654
            throw new CreateFeatureException(e, getName());
2655
        }
2656
    }
2657

    
2658
    private FeatureProvider createNewFeatureProvider(FeatureType type)
2659
        throws DataException {
2660
        type = this.fixFeatureType((DefaultFeatureType) type);
2661
        FeatureProvider data = this.provider.createFeatureProvider(type);
2662
        data.setNew(true);
2663
        if (type.hasOID() && (data.getOID() == null)) {
2664
            data.setOID(this.provider.createNewOID());
2665
        } else {
2666
            data.setOID(this.getTemporalOID());
2667
        }
2668
        return data;
2669

    
2670
    }
2671

    
2672
    @Override
2673
    public EditableFeature createNewFeature(FeatureType type,
2674
        boolean defaultValues) throws DataException {
2675
        try {
2676
            FeatureProvider data = createNewFeatureProvider(type);
2677
            DefaultEditableFeature feature =
2678
                new DefaultEditableFeature(this, data);
2679
            if (defaultValues) {
2680
                feature.initializeValues();
2681
            }
2682
            return feature;
2683
        } catch (Exception e) {
2684
            throw new CreateFeatureException(e, getName());
2685
        }
2686
    }
2687

    
2688
    @Override
2689
    public EditableFeature createNewFeature(boolean defaultValues)
2690
        throws DataException {
2691
        return this.createNewFeature(this.getDefaultFeatureType(),
2692
            defaultValues);
2693
    }
2694

    
2695
    @Override
2696
    public EditableFeature createNewFeature() throws DataException {
2697
        return this.createNewFeature(this.getDefaultFeatureType(), true);
2698
    }
2699

    
2700
    @Override
2701
    public EditableFeature createNewFeature(Feature defaultValues) throws DataException {
2702
        FeatureType ft = this.getDefaultFeatureType();
2703
        EditableFeature f = this.createNewFeature(ft, false);
2704
        f.copyFrom(defaultValues);
2705
        return f;
2706
    }
2707

    
2708
    @Override
2709
    public EditableFeature createNewFeature(JsonObject defaultValues) throws DataException {
2710
        FeatureType ft = this.getDefaultFeatureType();
2711
        EditableFeature f = this.createNewFeature(ft, false);
2712
        f.copyFrom(defaultValues);
2713
        return f;
2714
    }
2715

    
2716
    @Override
2717
    public EditableFeatureType createFeatureType() {
2718
        EditableFeatureType ftype = new DefaultEditableFeatureType(this);
2719
        return ftype;
2720
    }
2721

    
2722
    @Override
2723
    public EditableFeatureType createFeatureType(String id) {
2724
        DefaultEditableFeatureType ftype = new DefaultEditableFeatureType(this, id);
2725
        return ftype;
2726
    }
2727

    
2728
    //
2729
    // ====================================================================
2730
    // Index related methods
2731
    //
2732

    
2733
    @Override
2734
    public FeatureIndexes getIndexes() {
2735
        return this.indexes;
2736
    }
2737

    
2738
    @Override
2739
    public FeatureIndex createIndex(FeatureType featureType,
2740
        String attributeName, String indexName) throws DataException {
2741
        return createIndex(null, featureType, attributeName, indexName);
2742
    }
2743

    
2744
    @Override
2745
    public FeatureIndex createIndex(String indexTypeName,
2746
        FeatureType featureType, String attributeName, String indexName)
2747
        throws DataException {
2748

    
2749
        return createIndex(indexTypeName, featureType, attributeName,
2750
            indexName, false, null);
2751
    }
2752

    
2753
    @Override
2754
    public FeatureIndex createIndex(FeatureType featureType,
2755
        String attributeName, String indexName, Observer observer)
2756
        throws DataException {
2757
        return createIndex(null, featureType, attributeName, indexName,
2758
            observer);
2759
    }
2760

    
2761
    @Override
2762
    public FeatureIndex createIndex(String indexTypeName,
2763
        FeatureType featureType, String attributeName, String indexName,
2764
        final Observer observer) throws DataException {
2765

    
2766
        return createIndex(indexTypeName, featureType, attributeName,
2767
            indexName, true, observer);
2768
    }
2769

    
2770
    private FeatureIndex createIndex(String indexTypeName,
2771
        FeatureType featureType, String attributeName, String indexName,
2772
        boolean background, final Observer observer) throws DataException {
2773

    
2774
        checkNotInAppendMode();
2775
        FeatureIndexProviderServices index;
2776
        index = dataManager.createFeatureIndexProvider(indexTypeName, this,
2777
                featureType, indexName,
2778
                featureType.getAttributeDescriptor(attributeName));
2779

    
2780
        try {
2781
            index.fill(background, observer);
2782
        } catch (FeatureIndexException e) {
2783
            throw new InitializeException(index.getName(), e);
2784
        }
2785

    
2786
        ((DefaultFeatureIndexes) getIndexes()).addIndex(index);
2787
        return index;
2788
    }
2789

    
2790
    //
2791
    // ====================================================================
2792
    // Transforms related methods
2793
    //
2794

    
2795
    @Override
2796
    public FeatureStoreTransforms getTransforms() {
2797
        return this.transforms;
2798
    }
2799

    
2800
    @Override
2801
    public FeatureQuery createFeatureQuery() {
2802
        return new DefaultFeatureQuery();
2803
    }
2804
    
2805
    public FeatureQuery createFeatureQuery(Expression filter, String sortBy, boolean asc) {
2806
        FeatureQuery query = null;
2807
        if( filter!=null ) {
2808
            query = this.createFeatureQuery();
2809
            query.setFilter(filter);
2810
        }
2811
        if( !StringUtils.isEmpty(sortBy) ) {
2812
            if( query == null ) {
2813
                query = this.createFeatureQuery();
2814
            }
2815
            String[] attrnames;
2816
            if( sortBy.contains(",") ) {
2817
                attrnames = StringUtils.split(sortBy, ",");
2818
            } else {
2819
                attrnames = new String[] { sortBy };
2820
            }
2821
            for (String attrname : attrnames) {
2822
                attrname = attrname.trim();
2823
                if( attrname.startsWith("-") ) {
2824
                    query.getOrder().add(sortBy.substring(1).trim(), false);
2825
                } else if( attrname.endsWith("-") ) { 
2826
                    query.getOrder().add(sortBy.substring(0,sortBy.length()-1).trim(), false);
2827
                } else if( attrname.startsWith("+") ) {
2828
                    query.getOrder().add(sortBy.substring(1).trim(), true);
2829
                } else if( attrname.endsWith("-") ) { 
2830
                    query.getOrder().add(sortBy.substring(0,sortBy.length()-1).trim(), true);
2831
                } else {
2832
                    query.getOrder().add(sortBy, asc);
2833
                }
2834
            }
2835
        }
2836
        if( query != null ) {
2837
            query.retrievesAllAttributes();
2838
        }
2839
        return query;
2840
    }
2841
    
2842
    public FeatureQuery createFeatureQuery(String filter, String sortBy, boolean asc) {
2843
        if( StringUtils.isBlank(filter) ) {
2844
            return this.createFeatureQuery(
2845
                    (Expression)null, 
2846
                    sortBy, 
2847
                    asc
2848
            );
2849
        } else {
2850
            return this.createFeatureQuery(
2851
                    ExpressionUtils.createExpression(filter), 
2852
                    sortBy, 
2853
                    asc
2854
            );
2855
        }
2856
    }
2857
    
2858
    @Override
2859
    public DataQuery createQuery() {
2860
        return createFeatureQuery();
2861
    }
2862

    
2863
    //
2864
    // ====================================================================
2865
    // UndoRedo related methods
2866
    //
2867

    
2868
    @Override
2869
    public boolean canRedo() {
2870
        return commands.canRedo();
2871
    }
2872

    
2873
    @Override
2874
    public boolean canUndo() {
2875
        return commands.canUndo();
2876
    }
2877

    
2878
    @Override
2879
    public void redo(int num) throws RedoException {
2880
        for (int i = 0; i < num; i++) {
2881
            redo();
2882
        }
2883
    }
2884

    
2885
    @Override
2886
    public void undo(int num) throws UndoException {
2887
        for (int i = 0; i < num; i++) {
2888
            undo();
2889
        }
2890
    }
2891

    
2892
    //
2893
    // ====================================================================
2894
    // Metadata related methods
2895
    //
2896

    
2897
    @Override
2898
    public Object getMetadataID() {
2899
        return this.provider.getSourceId();
2900
    }
2901

    
2902
    @Override
2903
    public void delegate(DynObject dynObject) {
2904
        this.metadata.delegate(dynObject);
2905
    }
2906

    
2907
    @Override
2908
    public DynClass getDynClass() {
2909
        return this.metadata.getDynClass();
2910
    }
2911

    
2912
    @Override
2913
    public Object getDynValue(String name) throws DynFieldNotFoundException {
2914
        try {
2915
            if (this.transforms.hasDynValue(name)) {
2916
                return this.transforms.getDynValue(name);
2917
            }
2918
            if (this.metadata.hasDynValue(name)) {
2919
                return this.metadata.getDynValue(name);
2920
            }
2921
            if (METADATA_PROVIDER.equalsIgnoreCase(name)) {
2922
                return this.provider.getProviderName();
2923
            } else if (METADATA_CONTAINERNAME.equalsIgnoreCase(name)) {
2924
                return this.provider.getSourceId();
2925
            } else if (METADATA_FEATURETYPE.equalsIgnoreCase(name)) {
2926
                try {
2927
                    return this.getDefaultFeatureType();
2928
                } catch (DataException e) {
2929
                    return null;
2930
                }
2931
            }
2932
            return this.metadata.getDynValue(name);
2933
        } catch(Exception ex ) {
2934
            LOGGER.debug("Can't retrieve the value of '"+name+"' in store '"+this.getName()+"'.",ex);
2935
            return null;
2936
        }
2937
    }
2938

    
2939
    @Override
2940
    public boolean hasDynValue(String name) {
2941
        if (this.transforms.hasDynValue(name)) {
2942
            return true;
2943
        }
2944
        return this.metadata.hasDynValue(name);
2945
    }
2946

    
2947
    @Override
2948
    public boolean hasDynMethod(String name) {
2949
        return ((DynObject_v2)this.metadata).hasDynMethod(name);
2950
    }
2951

    
2952
    @Override
2953
    public void implement(DynClass dynClass) {
2954
        this.metadata.implement(dynClass);
2955
    }
2956

    
2957
    @Override
2958
    public Object invokeDynMethod(String name, Object[] args)
2959
        throws DynMethodException {
2960
        return this.metadata.invokeDynMethod(this, name, args);
2961
    }
2962

    
2963
    @Override
2964
    public Object invokeDynMethod(int code, Object[] args)
2965
        throws DynMethodException {
2966
        return this.metadata.invokeDynMethod(this, code, args);
2967
    }
2968

    
2969
    @Override
2970
    public void setDynValue(String name, Object value)
2971
        throws DynFieldNotFoundException {
2972
                if( this.transforms.hasDynValue(name) ) {
2973
                        this.transforms.setDynValue(name, value);
2974
                        return;
2975
                }
2976
        this.metadata.setDynValue(name, value);
2977

    
2978
    }
2979

    
2980
    /*
2981
     * (non-Javadoc)
2982
     *
2983
     * @see org.gvsig.metadata.Metadata#getMetadataChildren()
2984
     */
2985
    @Override
2986
    public Set getMetadataChildren() {
2987
        return this.metadataChildren;
2988
    }
2989

    
2990
    /*
2991
     * (non-Javadoc)
2992
     *
2993
     * @see org.gvsig.metadata.Metadata#getMetadataName()
2994
     */
2995
    @Override
2996
    public String getMetadataName() {
2997
        return this.provider.getProviderName();
2998
    }
2999

    
3000
    public FeatureTypeManager getFeatureTypeManager() {
3001
        return this.featureTypeManager;
3002
    }
3003

    
3004
    @Override
3005
    public long getFeatureCount() throws DataException {
3006
        if (featureCount == null) {
3007
            featureCount = this.provider.getFeatureCount();
3008
        }
3009
        if (this.isEditing()) {
3010
            if(this.isAppending()) {
3011
                try{
3012
                    throw new IllegalStateException();
3013
                } catch(IllegalStateException e) {
3014
                    LOGGER.info("Call DefaultFeatureStore.getFeatureCount editing in mode APPEND",e);
3015
                }
3016
                return -1;
3017
            } else {
3018
                return featureCount
3019
                    + this.featureManager.getDeltaSize();
3020
            }
3021
        }
3022
        return featureCount;
3023
    }
3024

    
3025
    private Long getTemporalOID() {
3026
        return this.temporalOid++;
3027
    }
3028

    
3029
    @Override
3030
    public FeatureType getProviderFeatureType(String featureTypeId) {
3031
        if (featureTypeId == null) {
3032
            return this.defaultFeatureType;
3033
        }
3034
        FeatureType type;
3035
        Iterator iter = this.featureTypes.iterator();
3036
        while (iter.hasNext()) {
3037
            type = (FeatureType) iter.next();
3038
            if (type.getId().equals(featureTypeId)) {
3039
                return type;
3040
            }
3041
        }
3042
        return null;
3043
    }
3044

    
3045
    @Override
3046
    public FeatureProvider getFeatureProviderFromFeature(Feature feature) {
3047
        return ((DefaultFeature) feature).getData();
3048
    }
3049

    
3050
    @Override
3051
    public DataStore getStore() {
3052
        return this;
3053
    }
3054

    
3055
    @Override
3056
    public FeatureStore getFeatureStore() {
3057
        return this;
3058
    }
3059

    
3060
    @Override
3061
    public void createCache(String name, DynObject parameters)
3062
        throws DataException {
3063
        cache = dataManager.createFeatureCacheProvider(name, parameters);
3064
        if (cache == null) {
3065
            throw new CreateException("FeaureCacheProvider", null);
3066
        }
3067
        cache.apply(this, provider);
3068
        provider = cache;
3069

    
3070
        featureCount = null;
3071
    }
3072

    
3073
    @Override
3074
    public FeatureCache getCache() {
3075
        return cache;
3076
    }
3077

    
3078
    @Override
3079
    public void clear() {
3080
        if (metadata != null) {
3081
            metadata.clear();
3082
        }
3083
    }
3084

    
3085
    @Override
3086
    public String getName() {
3087
        if( this.provider != null ) {
3088
            return this.provider.getName();
3089
        }
3090
        if( this.parameters instanceof HasAFile ) {
3091
            return FilenameUtils.getName(((HasAFile)this.parameters).getFile().getName());
3092
        }
3093
        return "unknow";
3094
    }
3095

    
3096
    @Override
3097
    public String getFullName() {
3098
        try {
3099
            if( this.provider!=null ) {
3100
                return this.provider.getFullName();
3101
            }
3102
            if( this.parameters instanceof HasAFile ) {
3103
                return (((HasAFile)this.parameters).getFile().getAbsolutePath());
3104
            }
3105
            return null;
3106
        } catch(Throwable th) {
3107
            return null;
3108
        }
3109
    }
3110

    
3111
    @Override
3112
    public String getProviderName() {
3113
        if( this.provider!=null ) {
3114
            return this.provider.getProviderName();
3115
        }
3116
        if( this.parameters != null ) {
3117
            return this.parameters.getDataStoreName();
3118
        }
3119
        return null;
3120

    
3121
    }
3122

    
3123
    @Override
3124
    public boolean isKnownEnvelope() {
3125
        return this.provider.isKnownEnvelope();
3126
    }
3127

    
3128
    @Override
3129
    public boolean hasRetrievedFeaturesLimit() {
3130
        return this.provider.hasRetrievedFeaturesLimit();
3131
    }
3132

    
3133
    @Override
3134
    public int getRetrievedFeaturesLimit() {
3135
        return this.provider.getRetrievedFeaturesLimit();
3136
    }
3137

    
3138
    @Override
3139
    public Interval getInterval() {
3140
        if( this.timeSupport!=null ) {
3141
            return this.timeSupport.getInterval();
3142
        }
3143
        try {
3144
            FeatureType type = this.getDefaultFeatureType();
3145
            FeatureAttributeDescriptor attr = type.getDefaultTimeAttribute();
3146
            if( attr!=null ) {
3147
                Interval interval = attr.getInterval();
3148
                if( interval!=null ) {
3149
                    return interval;
3150
                }
3151
            }
3152
        } catch (DataException ex) {
3153
        }
3154
        return this.provider.getInterval();
3155
    }
3156

    
3157
    @Override
3158
    public Collection getTimes() {
3159
        if( this.timeSupport!=null ) {
3160
            return this.timeSupport.getTimes();
3161
        }
3162
        return this.provider.getTimes();
3163
    }
3164

    
3165
    @Override
3166
    public Collection getTimes(Interval interval) {
3167
        if( this.timeSupport!=null ) {
3168
            return this.timeSupport.getTimes(interval);
3169
        }
3170
        return this.provider.getTimes(interval);
3171
    }
3172

    
3173
    public void setTimeSupport(FeatureStoreTimeSupport timeSupport) {
3174
        if( this.isEditing() ) {
3175
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' while store is editing.");
3176
        }
3177
        if( !this.transforms.isEmpty() ) {
3178
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"' if has transforms.");
3179
        }
3180
        FeatureType ft = this.defaultFeatureType;
3181
        FeatureAttributeDescriptor attr = ft.getAttributeDescriptor(timeSupport.getRequiredFieldNames()[0]);
3182
        if( attr == null ) {
3183
            throw new RuntimeException("Can't add time support over attribute '"+timeSupport.getAttributeName()+"', this attribute don't exists.");
3184
        }
3185
        EditableFeatureType eft = ft.getEditable();
3186
        attr = eft.getAttributeDescriptor(timeSupport.getAttributeName());
3187
        if( attr != null ) {
3188
            if( !(attr.getFeatureAttributeEmulator() instanceof FeatureStoreTimeSupport) ) {
3189
                throw new RuntimeException("Can't add time support, attribute '"+timeSupport.getAttributeName()+"'already exists.");
3190
            }
3191
            eft.remove(attr.getName());
3192
        }
3193
        EditableFeatureAttributeDescriptor attrTime = eft.add(
3194
            timeSupport.getAttributeName(), 
3195
            timeSupport.getDataType()
3196
        );
3197
        attrTime.setIsTime(true);
3198
        attrTime.setFeatureAttributeEmulator(timeSupport);
3199
        eft.setDefaultTimeAttributeName(timeSupport.getAttributeName());
3200
        this.defaultFeatureType = eft.getNotEditableCopy();
3201
        
3202
        this.timeSupport = timeSupport;
3203
    }
3204

    
3205
    @Override
3206
    @SuppressWarnings("CloneDoesntCallSuperClone")
3207
    public Object clone() throws CloneNotSupportedException {
3208

    
3209
        DataStoreParameters dsp = getParameters();
3210

    
3211
        DefaultFeatureStore cloned_store = null;
3212

    
3213
        try {
3214
            cloned_store = (DefaultFeatureStore) DALLocator.getDataManager().
3215
                openStore(this.getProviderName(), dsp);
3216
            if (transforms != null) {
3217
                cloned_store.transforms = (DefaultFeatureStoreTransforms) transforms.clone();
3218
                cloned_store.transforms.setStoreForClone(cloned_store);
3219
            }
3220
        } catch (Exception e) {
3221
            throw new CloneException(e);
3222
        }
3223
        return cloned_store;
3224

    
3225
    }
3226

    
3227
    @Override
3228
    public Feature getFeature(DynObject dynobject) {
3229
        if (dynobject instanceof DynObjectFeatureFacade){
3230
            Feature f = ((DynObjectFeatureFacade)dynobject).getFeature();
3231
            return f;
3232
        }
3233
        return null;
3234
    }
3235

    
3236
    @Override
3237
    public Iterator iterator() {
3238
        FeatureSet fset = null;
3239
        try {
3240
            fset  = this.getFeatureSet();
3241
            return fset.fastIterator();
3242
        } catch (DataException ex) {
3243
            throw new RuntimeException(ex);
3244
        } finally {
3245
            DisposeUtils.disposeQuietly(fset);
3246
        }
3247
    }
3248

    
3249
    @Override
3250
    public long size64() {
3251
        FeatureSet fset = null;
3252
        try {
3253
            fset  = this.getFeatureSet();
3254
            return fset.getSize();
3255
        } catch (DataException ex) {
3256
            throw new RuntimeException(ex);
3257
        } finally {
3258
            DisposeUtils.disposeQuietly(fset);
3259
        }
3260
    }
3261
   
3262
    @Override
3263
    public ExpressionBuilder createExpressionBuilder() {
3264
        ExpressionBuilder builder = GeometryExpressionUtils.createExpressionBuilder();
3265
        return builder;
3266
    }
3267

    
3268
    @Override
3269
    public ExpressionBuilder createExpression() {
3270
        return createExpressionBuilder();
3271
    }
3272

    
3273
    public FeatureSet features() throws DataException {
3274
        // This is to avoid jython to create a property with this name
3275
        // to access method getFeatures.
3276
        return this.getFeatureSet();
3277
    }
3278

    
3279
    @Override
3280
    public DataStoreProviderFactory getProviderFactory() {
3281
        DataStoreProviderFactory factory = dataManager.getStoreProviderFactory(parameters.getDataStoreName());
3282
        return factory;
3283
    }
3284

    
3285
    @Override
3286
    public void useCache(String providerName, DynObject parameters) throws DataException {
3287
        throw new UnsupportedOperationException();
3288
    }
3289

    
3290
    @Override
3291
    public boolean isBroken() {
3292
        return this.state.isBroken();
3293
    }
3294

    
3295
    @Override
3296
    public Throwable getBreakingsCause() {
3297
            return this.state.getBreakingsCause();
3298
    }
3299

    
3300
    @Override
3301
    public SpatialIndex wrapSpatialIndex(SpatialIndex index) {
3302
      FeatureStoreProviderFactory factory = (FeatureStoreProviderFactory) this.getProviderFactory();
3303
      if( !factory.supportNumericOID() ) {
3304
          return null;
3305
      }
3306
      SpatialIndex wrappedIndex = new WrappedSpatialIndex(index, this);
3307
      return wrappedIndex;
3308
  }
3309

    
3310
    @Override
3311
    public FeatureReference getFeatureReference(String code) {
3312
        FeatureReference featureReference = new DefaultFeatureReference(this, code);
3313
        return featureReference;
3314
    }
3315

    
3316
    @Override
3317
    public long getPendingChangesCount() {
3318
        if( this.featureManager==null ) {
3319
            return 0;
3320
        }
3321
        return this.featureManager.getPendingChangesCount();
3322
    }
3323

    
3324
    @Override
3325
    public ResourcesStorage getResourcesStorage() {
3326
        ResourcesStorage resourcesStorage;
3327
        try {
3328
            resourcesStorage = this.provider.getResourcesStorage();
3329
            if( resourcesStorage!=null ) {
3330
                return resourcesStorage;
3331
            }
3332
        } catch(Throwable th) {
3333
            
3334
        }
3335
        try {
3336
            DataServerExplorer explorer = this.getExplorer();
3337
            if( explorer==null ) {
3338
                return null;
3339
            }
3340
            resourcesStorage = explorer.getResourcesStorage(this);
3341
            explorer.dispose();
3342
            return resourcesStorage;
3343
        } catch (Exception ex) {
3344
            LOGGER.warn("Can't create resources storage",ex);
3345
            return null;
3346
        }
3347
    }
3348

    
3349
    @Override
3350
    public StoresRepository getStoresRepository() {
3351
        final StoresRepository mainRepository = this.dataManager.getStoresRepository();
3352
        StoresRepository localRepository = this.provider.getStoresRepository();
3353
        if( localRepository==null ) {
3354
            return mainRepository;
3355
        }
3356
        StoresRepository repository = new BaseStoresRepository(this.getName());
3357
        repository.addRepository(localRepository);
3358
        repository.addRepository(mainRepository);
3359
        return repository;
3360
    }
3361

    
3362
    @Override
3363
    public Feature getSampleFeature() {
3364
            Feature sampleFeature;
3365
            try {
3366
                FeatureSelection theSelection = this.getFeatureSelection();
3367
                if( theSelection!=null && !theSelection.isEmpty() ) {
3368
                    sampleFeature = theSelection.first();
3369
                } else {
3370
                    sampleFeature = this.first();
3371
                }
3372
                if( sampleFeature==null ) {
3373
                    sampleFeature = this.createNewFeature();
3374
                }
3375
            } catch (DataException ex) {
3376
                return null;
3377
            }
3378
            return sampleFeature;
3379
    }
3380

    
3381
    @Override
3382
    public boolean supportReferences() {
3383
        try {
3384
            return this.getDefaultFeatureType().supportReferences();
3385
        } catch (Exception ex) {
3386
            return false;
3387
        }
3388
    }
3389

    
3390
    @Override
3391
    public boolean isTemporary() {
3392
        if( this.provider==null ) {
3393
            return true;
3394
        }
3395
        return this.provider.isTemporary();
3396
    }
3397
    
3398
    public FeatureType getOriginalFeatureType(FeatureType featureType)  {
3399
        // FIXME this don't work for Store.fType.size() > 1
3400
        FeatureTypeManager manager = this.featureTypeManager;
3401
         if (manager==null) {
3402
             return null;
3403
         }
3404
         FeatureType originalFeatureType = manager.getOriginalFeatureType();
3405
         if (originalFeatureType==null) {
3406
             return null;
3407
         }
3408
         return originalFeatureType.getCopy();
3409
    }
3410

    
3411
    @Override
3412
    public Object getProperty(String name) {
3413
        if( this.propertiesSupportHelper==null ) {
3414
            return null;
3415
        }
3416
        return this.propertiesSupportHelper.getProperty(name);
3417
    }
3418

    
3419
    @Override
3420
    public void setProperty(String name, Object value) {
3421
        if( this.propertiesSupportHelper==null ) {
3422
            this.propertiesSupportHelper = new PropertiesSupportHelper();
3423
        }
3424
        this.propertiesSupportHelper.setProperty(name,value);
3425
    }
3426

    
3427
    @Override
3428
    public Map<String, Object> getProperties() {
3429
        if( this.propertiesSupportHelper==null ) {
3430
            return Collections.EMPTY_MAP;
3431
        }
3432
        return this.propertiesSupportHelper.getProperties();
3433
    }
3434
    
3435

    
3436

    
3437
}