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

History | View | Annotate | Download (23.6 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.ExpressionUtils;
33
import org.gvsig.expressionevaluator.GeometryExpressionBuilder;
34
import org.gvsig.expressionevaluator.GeometryExpressionUtils;
35
import org.gvsig.fmap.dal.DataStore;
36
import org.gvsig.fmap.dal.EditingNotification;
37
import org.gvsig.fmap.dal.EditingNotificationManager;
38
import org.gvsig.fmap.dal.exception.DataException;
39
import org.gvsig.fmap.dal.feature.EditableFeature;
40
import org.gvsig.fmap.dal.feature.Feature;
41
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
42
import org.gvsig.fmap.dal.feature.FeatureReference;
43
import org.gvsig.fmap.dal.feature.FeatureSet;
44
import org.gvsig.fmap.dal.feature.FeatureStore;
45
import org.gvsig.fmap.dal.feature.FeatureStoreProviderFactory;
46
import org.gvsig.fmap.dal.feature.FeatureType;
47
import org.gvsig.fmap.dal.swing.DALSwingLocator;
48
import org.gvsig.fmap.geom.Geometry;
49
import org.gvsig.fmap.geom.GeometryLocator;
50
import org.gvsig.fmap.geom.GeometryManager;
51
import org.gvsig.fmap.geom.GeometryUtils;
52
import org.gvsig.fmap.geom.SpatialIndex;
53
import org.gvsig.fmap.geom.type.GeometryType;
54
import org.gvsig.tools.dispose.DisposableIterator;
55
import org.gvsig.tools.exception.BaseException;
56
import org.gvsig.tools.util.PropertiesSupportHelper;
57
import org.gvsig.tools.visitor.VisitCanceledException;
58
import org.gvsig.tools.visitor.Visitor;
59
import org.gvsig.topology.lib.api.CancelOperationException;
60
import org.gvsig.topology.lib.api.PerformOperationException;
61
import org.gvsig.topology.lib.api.TopologyDataSet;
62
import org.gvsig.topology.lib.api.TopologyLocator;
63
import org.gvsig.topology.lib.api.TopologyManager;
64
import org.json.JSONObject;
65
import org.gvsig.topology.lib.api.TopologyServices;
66
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
68

    
69
/**
70
 *
71
 * @author jjdelcerro
72
 */
73
@SuppressWarnings({"EqualsAndHashcode","UseSpecificCatch"})
74
public class DefaultTopologyDataSet implements TopologyDataSet {
75

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

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

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

    
126
    @Override
127
    public String getName() {
128
        return this.name;
129
    }
130

    
131
    @Override
132
    public void setName(String name) {
133
        this.name = name;
134
    }
135

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

    
147
    @Override
148
    public DataStore getStore() {
149
        if (this.store == null) {
150
            this.store = this.services.getFeatureStore(this);
151
        }
152
        return this.store;
153
    }
154

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

    
163
    @Override
164
    public long getSize() {
165
        try {
166
            long size = this.getFeatureStore().getFeatureCount();
167
            return size;
168
        } catch (DataException ex) {
169
            // TODO: mensage al log
170
            return 0;
171
        }
172
    }
173

    
174
    @Override
175
    public boolean isThisStore(FeatureStore store) {
176
        if( store == null ) {
177
            return false;
178
        }
179
        return StringUtils.equals(this.fullName, store.getFullName());
180
    }
181
    
182
    @Override
183
    public int getGeometryType() {
184
        try {
185
            FeatureStore theStore = this.getFeatureStore();
186
            FeatureType featureType = theStore.getDefaultFeatureType();
187
            FeatureAttributeDescriptor attr = featureType.getDefaultGeometryAttribute();
188
            GeometryType geomType = attr.getGeomType();
189
            return geomType.getType();
190
        } catch (Exception ex) {
191
            return Geometry.TYPES.GEOMETRY;
192
        }
193
    }
194

    
195
    @Override
196
    public void accept(Visitor visitor) throws VisitCanceledException {
197
        FeatureStore st = this.getFeatureStore();
198
        try {
199
            st.accept(visitor);
200
        } catch(VisitCanceledException ex) {
201
            throw ex;
202
        } catch(BaseException ex) {
203
            throw new RuntimeException(ex);
204
        }
205
    }
206

    
207
    @Override
208
    public void edit() throws DataException {
209
        FeatureStore theStore = this.getFeatureStore();
210
        if (!theStore.isEditing()) {
211
            theStore.edit();
212
            this.needFinishEditing = true;
213
        }
214
    }
215

    
216
    @Override
217
    public void finishEditing() throws DataException {
218
        if (this.needFinishEditing) {
219
            this.getFeatureStore().finishEditing();
220
        }
221
    }
222

    
223
    @Override
224
    public EditableFeature createNewFeature() throws DataException {
225
        EditableFeature f = this.getFeatureStore().createNewFeature();
226
        return f;
227
    }
228

    
229
    public void perform(
230
            String operation,
231
            Feature feature
232
    ) throws DataException {
233
        this.edit();
234

    
235
        EditingNotificationManager editingNotificationManager
236
                = DALSwingLocator.getEditingNotificationManager();
237
        FeatureStore theStore = this.getFeatureStore();
238
        
239
        EditingNotification notification
240
                = editingNotificationManager.notifyObservers(this, // source
241
                        operation, // type
242
                        null,// document
243
                        null,// layer
244
                        theStore,// store
245
                        feature// feature
246
                );
247

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

    
273
                case EditingNotification.BEFORE_INSERT_FEATURE:
274
                    theStore.insert((EditableFeature) feature);
275
                    after = EditingNotification.AFTER_INSERT_FEATURE;
276
                    break;
277
            }
278
        }
279

    
280
        editingNotificationManager.notifyObservers(this,
281
                after, null, null,
282
                theStore, feature);
283

    
284
    }
285

    
286
    @Override
287
    public void insert(final EditableFeature feature) throws DataException {
288
        perform(
289
            EditingNotification.BEFORE_INSERT_FEATURE,
290
            feature
291
        );
292
    }
293

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

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

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

    
318
    @Override
319
    public JSONObject toJSON() {
320
        JSONObject jsonDataSet = new JSONObject();
321
        jsonDataSet.put("name", this.name);
322
        jsonDataSet.put("fullName", this.fullName);
323

    
324
        return jsonDataSet;
325
    }
326

    
327
    @Override
328
    public void fromJSON(String json) {
329
        this.fromJSON(new JSONObject(json));
330
    }
331

    
332
    @Override
333
    public void fromJSON(JSONObject json) {
334
        TopologyManager manager = TopologyLocator.getTopologyManager();
335
        this.name = json.getString("name");
336
        this.fullName = null;
337
        if( json.has("fullName") ) {
338
            this.fullName = json.getString("fullName");
339
        }
340
        this.store = null;
341
        this.needFinishEditing = false;
342
        this.services = manager.getDefaultServices();
343
    }
344

    
345
    @Override
346
    public Object getProperty(String string) {
347
        return this.propertiesHelper.getProperty(name);
348
    }
349

    
350
    @Override
351
    public void setProperty(String string, Object o) {
352
        this.propertiesHelper.setProperty(name, o);
353
    }
354

    
355
    @Override
356
    public Map<String, Object> getProperties() {
357
        return this.propertiesHelper.getProperties();
358
    }
359

    
360
    @Override
361
    public SpatialIndex getSpatialIndex() {
362
        if( this.spatialIndex == null ) {
363
            this.spatialIndex = new MutableObject<>();
364
            FeatureStore theStore = this.getFeatureStore();
365
            FeatureStoreProviderFactory storeFactory = (FeatureStoreProviderFactory) theStore.getProviderFactory();
366
            if( storeFactory.useLocalIndexesCanImprovePerformance()==FeatureStoreProviderFactory.YES ) {
367
                try {
368
                    GeometryManager geomManager = GeometryLocator.getGeometryManager();
369
                    final SpatialIndex geomIndex = geomManager.createSpatialIndex(
370
                            GeometryManager.SPATIALINDEX_DEFAULT_QUADTREE,
371
                            null
372
                    );
373
                    final SpatialIndex dataIndex = theStore.wrapSpatialIndex(geomIndex);
374
                    try {
375
                        store.accept((Object o) -> {
376
                            Feature f = (Feature) o;
377
                            Geometry geom = f.getDefaultGeometry();
378
                            if (geom != null) {
379
                                dataIndex.insert(geom, f);
380
                            }
381
                        });
382
                    } catch (VisitCanceledException ex) {
383
                    }
384
                    this.spatialIndex.setValue(dataIndex);
385
                } catch (Exception ex) {
386
                    LOGGER.warn("Can't create spatial index", ex);
387
                }
388
            }
389
        }
390
        return this.spatialIndex.getValue();
391
    }
392

    
393
    
394
    @Override
395
    public Iterable<FeatureReference>  getFeatureReferencesThatEnvelopeIntersectsWith(Geometry geom) {
396
        SpatialIndex index = this.getSpatialIndex();
397
        if( index == null ) {
398
            try {
399
                FeatureStore theStore = (FeatureStore) this.getStore();
400
                Expression expression = ExpressionUtils.createExpression();
401
                GeometryExpressionBuilder expressionBuilder = GeometryExpressionUtils.createExpressionBuilder();
402
                String geomName = theStore.getDefaultFeatureType().getDefaultGeometryAttributeName();
403
                if( GeometryUtils.isSubtype(Geometry.TYPES.POINT, geom.getType()) )  {
404
                    expression.setPhrase(
405
                        expressionBuilder.ifnull(
406
                            expressionBuilder.column(geomName),
407
                            expressionBuilder.constant(false),
408
                            expressionBuilder.ST_Intersects(
409
                                    expressionBuilder.column(geomName),
410
                                    expressionBuilder.geometry(geom)
411
                            )
412
                        ).toString()
413
                    );
414
                } else {
415
                    expression.setPhrase(
416
                        expressionBuilder.ifnull(
417
                            expressionBuilder.column(geomName),
418
                            expressionBuilder.constant(false),
419
                            expressionBuilder.ST_Intersects(
420
                                    expressionBuilder.column(geomName),
421
                                    expressionBuilder.envelope(geom.getEnvelope())
422
                            )
423
                        ).toString()
424
                    );
425
                }
426
                FeatureSet set = theStore.getFeatureSet(expression);
427
                final DisposableIterator it = set.fastIterator();
428
                return () -> new Iterator<FeatureReference>() {
429
                    @Override
430
                    public boolean hasNext() {
431
                        return it.hasNext();
432
                    }
433
                    
434
                    @Override
435
                    public FeatureReference next() {
436
                        Feature f = (Feature) it.next();
437
                        return f.getReference();
438
                    }
439
                };
440
                
441
            } catch(Exception ex) {
442
                return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR;
443
            }
444
        }
445
        final Iterator it = index.query(geom);
446
        if( it == null ) {
447
            return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR;
448
        }
449
        return () -> it;
450
    }
451
    
452
    @Override
453
    public Iterable<Feature>  getFeaturesThatEnvelopeIntersectsWith(Geometry geom) {
454
        SpatialIndex index = this.getSpatialIndex();
455
        if( index == null ) {
456
            try {
457
                FeatureStore theStore = (FeatureStore) this.getStore();
458
                Expression expression = ExpressionUtils.createExpression();
459
                GeometryExpressionBuilder expressionBuilder = GeometryExpressionUtils.createExpressionBuilder();
460
                String geomName = theStore.getDefaultFeatureType().getDefaultGeometryAttributeName();
461
                if( GeometryUtils.isSubtype(Geometry.TYPES.POINT, geom.getType()) )  {
462
                    expression.setPhrase(
463
                        expressionBuilder.ifnull(
464
                            expressionBuilder.column(geomName),
465
                            expressionBuilder.constant(false),
466
                            expressionBuilder.ST_Intersects(
467
                                    expressionBuilder.column(geomName),
468
                                    expressionBuilder.geometry(geom)
469
                            )
470
                        ).toString()
471
                    );
472
                } else {
473
                    expression.setPhrase(
474
                        expressionBuilder.ifnull(
475
                            expressionBuilder.column(geomName),
476
                            expressionBuilder.constant(false),
477
                            expressionBuilder.ST_Intersects(
478
                                    expressionBuilder.column(geomName),
479
                                    expressionBuilder.envelope(geom.getEnvelope())
480
                            )
481
                        ).toString()
482
                    );
483
                }
484
                FeatureSet set = theStore.getFeatureSet(expression);
485
                final DisposableIterator it = set.fastIterator();
486
                return () -> it;
487
                
488
            } catch(Exception ex) {
489
                return (Iterable<Feature>) IteratorUtils.EMPTY_ITERATOR;
490
            }
491
        }
492
        final Iterator it = index.query(geom);
493
        if( it == null ) {
494
            return (Iterable<Feature>) IteratorUtils.EMPTY_ITERATOR;
495
        }
496
        return () -> new Iterator<Feature>() {
497
            @Override
498
            public boolean hasNext() {
499
                return it.hasNext();
500
            }
501
            
502
            @Override
503
            public Feature next() {
504
                FeatureReference ref = (FeatureReference) it.next();
505
                try {
506
                    return ref.getFeature();
507
                } catch (DataException ex) {
508
                    return null;
509
                }
510
            }
511
        };
512
    }
513

    
514
    @Override
515
    public Iterable<FeatureReference> query(Geometry geom) {
516
        return this.queryReferences(geom);
517
    }
518
    
519
    @Override
520
    public Iterable<FeatureReference> queryReferences(Geometry geom) {
521
        SpatialIndex index = this.getSpatialIndex();
522
        if( index == null ) {
523
            try {
524
                FeatureStore theStore = (FeatureStore) this.getStore();
525
                Expression expression = ExpressionUtils.createExpression();
526
                GeometryExpressionBuilder expressionBuilder = GeometryExpressionUtils.createExpressionBuilder();
527
                String geomName = theStore.getDefaultFeatureType().getDefaultGeometryAttributeName();
528
                if( GeometryUtils.isSubtype(Geometry.TYPES.POINT, geom.getType()) )  {
529
                    expression.setPhrase(
530
                        expressionBuilder.ifnull(
531
                            expressionBuilder.column(geomName),
532
                            expressionBuilder.constant(false),
533
                            expressionBuilder.ST_Intersects(
534
                                    expressionBuilder.column(geomName),
535
                                    expressionBuilder.geometry(geom)
536
                            )
537
                        ).toString()
538
                    );
539
                } else {
540
                    expression.setPhrase(
541
                        expressionBuilder.ifnull(
542
                            expressionBuilder.column(geomName),
543
                            expressionBuilder.constant(false),
544
                            expressionBuilder.ST_Overlaps(
545
                                    expressionBuilder.column(geomName),
546
                                    expressionBuilder.envelope(geom.getEnvelope())
547
                            )
548
                        ).toString()
549
                    );
550
                }
551
                FeatureSet set = theStore.getFeatureSet(expression);
552
                final DisposableIterator it = set.fastIterator();
553
                return () -> new Iterator<FeatureReference>() {
554
                    @Override
555
                    public boolean hasNext() {
556
                        return it.hasNext();
557
                    }
558
                    
559
                    @Override
560
                    public FeatureReference next() {
561
                        Feature f = (Feature) it.next();
562
                        return f.getReference();
563
                    }
564
                };
565
                
566
            } catch(Exception ex) {
567
                return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR;
568
            }
569
        }
570
        final Iterator it = index.query(geom);
571
        if( it == null ) {
572
            return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR;
573
        }
574
        return () -> it;
575
    }
576

    
577
    @Override
578
    public Iterable<Feature> queryFeatures(Geometry geom) {
579
        SpatialIndex index = this.getSpatialIndex();
580
        if( index == null ) {
581
            try {
582
                FeatureStore theStore = (FeatureStore) this.getStore();
583
                Expression expression = ExpressionUtils.createExpression();
584
                GeometryExpressionBuilder expressionBuilder = GeometryExpressionUtils.createExpressionBuilder();
585
                String geomName = theStore.getDefaultFeatureType().getDefaultGeometryAttributeName();
586
                if( GeometryUtils.isSubtype(Geometry.TYPES.POINT, geom.getType()) )  {
587
                    expression.setPhrase(
588
                        expressionBuilder.ifnull(
589
                            expressionBuilder.column(geomName),
590
                            expressionBuilder.constant(false),
591
                            expressionBuilder.ST_Intersects(
592
                                    expressionBuilder.column(geomName),
593
                                    expressionBuilder.geometry(geom)
594
                            )
595
                        ).toString()
596
                    );
597
                } else {
598
                    expression.setPhrase(
599
                        expressionBuilder.ifnull(
600
                            expressionBuilder.column(geomName),
601
                            expressionBuilder.constant(false),
602
                            expressionBuilder.ST_Overlaps(
603
                                    expressionBuilder.column(geomName),
604
                                    expressionBuilder.envelope(geom.getEnvelope())
605
                            )
606
                        ).toString()
607
                    );
608
                }
609
                FeatureSet set = theStore.getFeatureSet(expression);
610
                final DisposableIterator it = set.fastIterator();
611
                return () -> it;
612
                
613
            } catch(Exception ex) {
614
                return (Iterable<Feature>) IteratorUtils.EMPTY_ITERATOR;
615
            }
616
        }
617
        final Iterator it = index.query(geom);
618
        if( it == null ) {
619
            return (Iterable<Feature>) IteratorUtils.EMPTY_ITERATOR;
620
        }
621
        return () -> new Iterator<Feature>() {
622
            @Override
623
            public boolean hasNext() {
624
                return it.hasNext();
625
            }
626
            
627
            @Override
628
            public Feature next() {
629
                FeatureReference ref = (FeatureReference) it.next();
630
                try {
631
                    return ref.getFeature();
632
                } catch (DataException ex) {
633
                    return null;
634
                }
635
            }
636
        };
637
    }
638

    
639
    @Override
640
    public Feature findFirst(Expression filter) {
641
        try {
642
            return this.getFeatureStore().findFirst(filter);
643
        } catch (Exception ex) {
644
            return null;
645
        }
646
    }
647

    
648
}