Statistics
| Revision:

gvsig-projects-pool / org.gvsig.topology / trunk / org.gvsig.topology / org.gvsig.topology.lib / org.gvsig.topology.lib.impl / src / main / java / org / gvsig / topology / lib / impl / DefaultTopologyDataSet.java @ 3637

History | View | Annotate | Download (19.8 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
package org.gvsig.topology.lib.impl;
25

    
26
import java.util.Iterator;
27
import java.util.Map;
28
import org.apache.commons.collections.IteratorUtils;
29
import org.apache.commons.lang3.StringUtils;
30
import org.apache.commons.lang3.mutable.MutableObject;
31
import org.gvsig.expressionevaluator.Expression;
32
import org.gvsig.expressionevaluator.ExpressionBuilder;
33
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
34
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
35
import org.gvsig.expressionevaluator.ExpressionUtils;
36
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
37
import org.gvsig.expressionevaluator.GeometryExpressionUtils;
38
import org.gvsig.fmap.dal.DataStore;
39
import org.gvsig.fmap.dal.EditingNotification;
40
import org.gvsig.fmap.dal.EditingNotificationManager;
41
import org.gvsig.fmap.dal.exception.DataException;
42
import org.gvsig.fmap.dal.feature.EditableFeature;
43
import org.gvsig.fmap.dal.feature.Feature;
44
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
45
import org.gvsig.fmap.dal.feature.FeatureReference;
46
import org.gvsig.fmap.dal.feature.FeatureSet;
47
import org.gvsig.fmap.dal.feature.FeatureStore;
48
import org.gvsig.fmap.dal.feature.FeatureStoreProviderFactory;
49
import org.gvsig.fmap.dal.feature.FeatureType;
50
import org.gvsig.fmap.dal.swing.DALSwingLocator;
51
import org.gvsig.fmap.geom.Geometry;
52
import org.gvsig.fmap.geom.GeometryLocator;
53
import org.gvsig.fmap.geom.GeometryManager;
54
import org.gvsig.fmap.geom.GeometryUtils;
55
import org.gvsig.fmap.geom.SpatialIndex;
56
import org.gvsig.fmap.geom.type.GeometryType;
57
import org.gvsig.tools.dispose.DisposableIterator;
58
import org.gvsig.tools.exception.BaseException;
59
import org.gvsig.tools.util.PropertiesSupportHelper;
60
import org.gvsig.tools.visitor.VisitCanceledException;
61
import org.gvsig.tools.visitor.Visitor;
62
import org.gvsig.topology.lib.api.CancelOperationException;
63
import org.gvsig.topology.lib.api.PerformOperationException;
64
import org.gvsig.topology.lib.api.TopologyDataSet;
65
import org.gvsig.topology.lib.api.TopologyLocator;
66
import org.gvsig.topology.lib.api.TopologyManager;
67
import org.json.JSONObject;
68
import org.gvsig.topology.lib.api.TopologyServices;
69
import org.slf4j.Logger;
70
import org.slf4j.LoggerFactory;
71

    
72
/**
73
 *
74
 * @author jjdelcerro
75
 */
76
@SuppressWarnings({"EqualsAndHashcode","UseSpecificCatch"})
77
public class DefaultTopologyDataSet implements TopologyDataSet {
78

    
79
    private final static Logger LOGGER = LoggerFactory.getLogger(DefaultTopologyDataSet.class);
80
    
81
    private TopologyServices services;
82
    private String name;
83
    private DataStore store;
84
    private boolean needFinishEditing;
85
    private String fullName;
86
    private PropertiesSupportHelper propertiesHelper;
87
    private MutableObject<SpatialIndex> spatialIndex = null;
88
    
89
    public DefaultTopologyDataSet() {
90
        this.services = null;
91
        this.name = null;
92
        this.store = null;
93
        this.needFinishEditing = false;
94
        this.fullName = null;
95
        this.propertiesHelper = new PropertiesSupportHelper();
96
    }
97

    
98
    public DefaultTopologyDataSet(TopologyServices services, String name, DataStore store) {
99
        this.services = services;
100
        this.name = name;
101
        this.store = store;
102
        this.needFinishEditing = false;
103
        if( store!=null ) {
104
            this.fullName = store.getFullName();
105
        }
106
    }
107

    
108
    @Override
109
    public void restart() {
110
        this.store  = null;
111
        this.spatialIndex = null;
112
    }
113
    
114
    @Override
115
    public boolean equals(Object obj) {
116
        if( !(obj instanceof DefaultTopologyDataSet) ) {
117
            return false;
118
        }
119
        DefaultTopologyDataSet other = (DefaultTopologyDataSet)obj;
120
        if( this.store != other.store ) {
121
            return false;
122
        }
123
        if( !StringUtils.equals(this.getName(), other.getName()) ) {
124
            return false;
125
        }
126
        return true;
127
    }
128

    
129
    @Override
130
    public String getName() {
131
        return this.name;
132
    }
133

    
134
    @Override
135
    public void setName(String name) {
136
        this.name = name;
137
    }
138

    
139
    @Override
140
    public String toString() {
141
        try {
142
            FeatureAttributeDescriptor attr = this.getFeatureStore().getDefaultFeatureType().getDefaultGeometryAttribute();
143
            String geomType = attr.getGeomType().getName();
144
            return this.name + " ("+ geomType + ")";
145
        } catch(Exception ex) {
146
            return this.name ;
147
        }
148
    }
149

    
150
    @Override
151
    public void setStore(DataStore store) {
152
        this.store = store;
153
    }
154

    
155
    @Override
156
    public DataStore getStore() {
157
        if (this.store == null) {
158
            this.store = this.services.getFeatureStore(this);
159
        }
160
        return this.store;
161
    }
162

    
163
    @Override
164
    public FeatureStore getFeatureStore() {
165
        if (this.store == null) {
166
            this.store = this.services.getFeatureStore(this);
167
        }
168
        return (FeatureStore) this.store;
169
    }
170

    
171
    @Override
172
    public long getSize() {
173
        try {
174
            long size = this.getFeatureStore().getFeatureCount();
175
            return size;
176
        } catch (DataException ex) {
177
            // TODO: mensage al log
178
            return 0;
179
        }
180
    }
181

    
182
    @Override
183
    public boolean isThisStore(FeatureStore store) {
184
        if( store == null ) {
185
            return false;
186
        }
187
        return StringUtils.equals(this.fullName, store.getFullName());
188
    }
189
    
190
    @Override
191
    public int getGeometryType() {
192
        try {
193
            FeatureStore theStore = this.getFeatureStore();
194
            FeatureType featureType = theStore.getDefaultFeatureType();
195
            FeatureAttributeDescriptor attr = featureType.getDefaultGeometryAttribute();
196
            GeometryType geomType = attr.getGeomType();
197
            return geomType.getType();
198
        } catch (Exception ex) {
199
            return Geometry.TYPES.GEOMETRY;
200
        }
201
    }
202

    
203
    @Override
204
    public void accept(Visitor visitor) throws VisitCanceledException {
205
        FeatureStore st = this.getFeatureStore();
206
        try {
207
            st.accept(visitor);
208
        } catch(VisitCanceledException ex) {
209
            throw ex;
210
        } catch(BaseException ex) {
211
            throw new RuntimeException(ex);
212
        }
213
    }
214

    
215
    @Override
216
    public void edit() throws DataException {
217
        FeatureStore theStore = this.getFeatureStore();
218
        if (!theStore.isEditing()) {
219
            theStore.edit();
220
            this.needFinishEditing = true;
221
        }
222
    }
223

    
224
    @Override
225
    public void finishEditing() throws DataException {
226
        if (this.needFinishEditing) {
227
            this.getFeatureStore().finishEditing();
228
        }
229
    }
230

    
231
    @Override
232
    public EditableFeature createNewFeature() throws DataException {
233
        EditableFeature f = this.getFeatureStore().createNewFeature();
234
        return f;
235
    }
236

    
237
    public void perform(
238
            String operation,
239
            Feature feature
240
    ) throws DataException {
241
        this.edit();
242

    
243
        EditingNotificationManager editingNotificationManager
244
                = DALSwingLocator.getEditingNotificationManager();
245
        FeatureStore theStore = this.getFeatureStore();
246
        
247
        EditingNotification notification
248
                = editingNotificationManager.notifyObservers(this, // source
249
                        operation, // type
250
                        null,// document
251
                        null,// layer
252
                        theStore,// store
253
                        feature// feature
254
                );
255

    
256
        if (notification.isCanceled()) {
257
            String msg = String.format(
258
                    "Can't insert feature into %1$s, canceled by some observer.",
259
                    this.getName());
260
            throw new CancelOperationException(msg);
261
        }
262
        
263
        String after = null;
264
        if( operation.equalsIgnoreCase(EditingNotification.BEFORE_REMOVE_FEATURE) ) {
265
            theStore.delete(feature);
266
            after = EditingNotification.AFTER_REMOVE_FEATURE;
267
            
268
        } else {
269
            if (notification.shouldValidateTheFeature()) {
270
                if (!editingNotificationManager.validateFeature(feature)) {
271
                    String msg = String.format("%1$s is not valid", feature.toString());
272
                    throw new PerformOperationException(msg);
273
                }
274
            }
275
            switch(operation) {
276
                case EditingNotification.BEFORE_UPDATE_FEATURE:
277
                    theStore.update((EditableFeature) feature);
278
                    after = EditingNotification.AFTER_UPDATE_FEATURE;
279
                    break;
280

    
281
                case EditingNotification.BEFORE_INSERT_FEATURE:
282
                    theStore.insert((EditableFeature) feature);
283
                    after = EditingNotification.AFTER_INSERT_FEATURE;
284
                    break;
285
            }
286
        }
287

    
288
        editingNotificationManager.notifyObservers(this,
289
                after, null, null,
290
                theStore, feature);
291

    
292
    }
293

    
294
    @Override
295
    public void insert(final EditableFeature feature) throws DataException {
296
        perform(
297
            EditingNotification.BEFORE_INSERT_FEATURE,
298
            feature
299
        );
300
    }
301

    
302
    @Override
303
    public void update(final EditableFeature feature) throws DataException {
304
        perform(
305
            EditingNotification.BEFORE_UPDATE_FEATURE,
306
            feature
307
        );
308
    }
309

    
310
    @Override
311
    public void delete(final Feature feature) throws DataException {
312
        perform(
313
            EditingNotification.BEFORE_REMOVE_FEATURE,
314
            feature
315
        );
316
    }
317

    
318
    @Override
319
    public void delete(final FeatureReference feature) throws DataException {
320
        perform(
321
            EditingNotification.BEFORE_REMOVE_FEATURE,
322
            feature.getFeature()
323
        );
324
    }
325

    
326
    @Override
327
    public JSONObject toJSON() {
328
        JSONObject jsonDataSet = new JSONObject();
329
        jsonDataSet.put("name", this.name);
330
        jsonDataSet.put("fullName", this.fullName);
331

    
332
        return jsonDataSet;
333
    }
334

    
335
    @Override
336
    public void fromJSON(String json) {
337
        this.fromJSON(new JSONObject(json));
338
    }
339

    
340
    @Override
341
    public void fromJSON(JSONObject json) {
342
        TopologyManager manager = TopologyLocator.getTopologyManager();
343
        this.name = json.getString("name");
344
        this.fullName = null;
345
        if( json.has("fullName") ) {
346
            this.fullName = json.getString("fullName");
347
        }
348
        this.store = null;
349
        this.needFinishEditing = false;
350
        this.services = manager.getDefaultServices();
351
    }
352

    
353
    @Override
354
    public Object getProperty(String string) {
355
        return this.propertiesHelper.getProperty(name);
356
    }
357

    
358
    @Override
359
    public void setProperty(String string, Object o) {
360
        this.propertiesHelper.setProperty(name, o);
361
    }
362

    
363
    @Override
364
    public Map<String, Object> getProperties() {
365
        return this.propertiesHelper.getProperties();
366
    }
367

    
368
    @Override
369
    public SpatialIndex getSpatialIndex() {
370
        if( this.spatialIndex == null ) {
371
            this.spatialIndex = new MutableObject<>();
372
            FeatureStore theStore = this.getFeatureStore();
373
            FeatureStoreProviderFactory storeFactory = (FeatureStoreProviderFactory) theStore.getProviderFactory();
374
            if( storeFactory.useLocalIndexesCanImprovePerformance()==FeatureStoreProviderFactory.YES ) {
375
                try {
376
                    GeometryManager geomManager = GeometryLocator.getGeometryManager();
377
                    final SpatialIndex geomIndex = geomManager.createSpatialIndex(
378
                            GeometryManager.SPATIALINDEX_DEFAULT_QUADTREE,
379
                            null
380
                    );
381
                    final SpatialIndex dataIndex = theStore.wrapSpatialIndex(geomIndex);
382
                    try {
383
                        store.accept(new Visitor() {
384
                            @Override
385
                            public void visit(Object o) throws VisitCanceledException, BaseException {
386
                                Feature f = (Feature) o;
387
                                Geometry geom = f.getDefaultGeometry();
388
                                if (geom != null) {
389
                                    dataIndex.insert(geom, f);
390
                                }
391
                            }
392
                        });
393
                    } catch (VisitCanceledException ex) {
394
                    }
395
                    this.spatialIndex.setValue(dataIndex);
396
                } catch (Exception ex) {
397
                    LOGGER.warn("Can't create spatial index", ex);
398
                }
399
            }
400
        }
401
        return this.spatialIndex.getValue();
402
    }
403

    
404
    @Override
405
    public Iterable<FeatureReference> query(Geometry geom) {
406
        return this.queryReferences(geom);
407
    }
408
    
409
    @Override
410
    public Iterable<FeatureReference> queryReferences(Geometry geom) {
411
        SpatialIndex index = this.getSpatialIndex();
412
        if( index == null ) {
413
            try {
414
                FeatureStore theStore = (FeatureStore) this.getStore();
415
                Expression expression = ExpressionUtils.createExpression();
416
                GeometryExpressionBuilder expressionBuilder = GeometryExpressionUtils.createExpressionBuilder();
417
                String geomName = theStore.getDefaultFeatureType().getDefaultGeometryAttributeName();
418
                if( GeometryUtils.isSubtype(Geometry.TYPES.POINT, geom.getType()) )  {
419
                    expression.setPhrase(
420
                        expressionBuilder.ifnull(
421
                            expressionBuilder.column(geomName),
422
                            expressionBuilder.constant(false),
423
                            expressionBuilder.ST_Intersects(
424
                                    expressionBuilder.column(geomName),
425
                                    expressionBuilder.geometry(geom)
426
                            )
427
                        ).toString()
428
                    );
429
                } else {
430
                    expression.setPhrase(
431
                        expressionBuilder.ifnull(
432
                            expressionBuilder.column(geomName),
433
                            expressionBuilder.constant(false),
434
                            expressionBuilder.ST_Overlaps(
435
                                    expressionBuilder.column(geomName),
436
                                    expressionBuilder.envelope(geom.getEnvelope())
437
                            )
438
                        ).toString()
439
                    );
440
                }
441
                FeatureSet set = theStore.getFeatureSet(expression);
442
                final DisposableIterator it = set.fastIterator();
443
                return new Iterable<FeatureReference>() {
444
                    @Override
445
                    public Iterator<FeatureReference> iterator() {
446
                        return new Iterator<FeatureReference>() {
447
                            @Override
448
                            public boolean hasNext() {
449
                                return it.hasNext();
450
                            }
451

    
452
                            @Override
453
                            public FeatureReference next() {
454
                                Feature f = (Feature) it.next();
455
                                return f.getReference();
456
                            }
457
                        };
458
                    }
459
                };
460
                
461
            } catch(Exception ex) {
462
                return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR;
463
            }
464
        }
465
        final Iterator it = index.query(geom);
466
        if( it == null ) {
467
            return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR;
468
        }
469
        return new Iterable<FeatureReference>() {
470
            @Override
471
            public Iterator<FeatureReference> iterator() {
472
                return it;
473
            }
474
        };
475
    }
476

    
477
    @Override
478
    public Iterable<Feature> queryFeatures(Geometry geom) {
479
        SpatialIndex index = this.getSpatialIndex();
480
        if( index == null ) {
481
            try {
482
                FeatureStore theStore = (FeatureStore) this.getStore();
483
                Expression expression = ExpressionUtils.createExpression();
484
                GeometryExpressionBuilder expressionBuilder = GeometryExpressionUtils.createExpressionBuilder();
485
                String geomName = theStore.getDefaultFeatureType().getDefaultGeometryAttributeName();
486
                if( GeometryUtils.isSubtype(Geometry.TYPES.POINT, geom.getType()) )  {
487
                    expression.setPhrase(
488
                        expressionBuilder.ifnull(
489
                            expressionBuilder.column(geomName),
490
                            expressionBuilder.constant(false),
491
                            expressionBuilder.ST_Intersects(
492
                                    expressionBuilder.column(geomName),
493
                                    expressionBuilder.geometry(geom)
494
                            )
495
                        ).toString()
496
                    );
497
                } else {
498
                    expression.setPhrase(
499
                        expressionBuilder.ifnull(
500
                            expressionBuilder.column(geomName),
501
                            expressionBuilder.constant(false),
502
                            expressionBuilder.ST_Overlaps(
503
                                    expressionBuilder.column(geomName),
504
                                    expressionBuilder.envelope(geom.getEnvelope())
505
                            )
506
                        ).toString()
507
                    );
508
                }
509
                FeatureSet set = theStore.getFeatureSet(expression);
510
                final DisposableIterator it = set.fastIterator();
511
                return new Iterable<Feature>() {
512
                    @Override
513
                    public Iterator<Feature> iterator() {
514
                        return it;
515
                    }
516
                };
517
                
518
            } catch(Exception ex) {
519
                return (Iterable<Feature>) IteratorUtils.EMPTY_ITERATOR;
520
            }
521
        }
522
        final Iterator it = index.query(geom);
523
        if( it == null ) {
524
            return (Iterable<Feature>) IteratorUtils.EMPTY_ITERATOR;
525
        }
526
        return new Iterable<Feature>() {
527
            @Override
528
            public Iterator<Feature> iterator() {
529
                return new Iterator<Feature>() {
530
                    @Override
531
                    public boolean hasNext() {
532
                        return it.hasNext();
533
                    }
534

    
535
                    @Override
536
                    public Feature next() {
537
                        FeatureReference ref = (FeatureReference) it.next();
538
                        try {
539
                            return ref.getFeature();
540
                        } catch (DataException ex) {
541
                            return null;
542
                        }
543
                    }
544
                };
545
            }
546
        };
547
    }
548

    
549
    @Override
550
    public Feature findFirst(Expression filter) {
551
        try {
552
            return this.getFeatureStore().findFirst(filter);
553
        } catch (Exception ex) {
554
            return null;
555
        }
556
    }
557

    
558
    void setTopologyServices(TopologyServices services) {
559
        this.services = services;
560
        this.restart();
561
    }
562

    
563
}