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

History | View | Annotate | Download (19.5 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.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(new Visitor() {
376
                            @Override
377
                            public void visit(Object o) throws VisitCanceledException, BaseException {
378
                                Feature f = (Feature) o;
379
                                Geometry geom = f.getDefaultGeometry();
380
                                if (geom != null) {
381
                                    dataIndex.insert(geom, f);
382
                                }
383
                            }
384
                        });
385
                    } catch (VisitCanceledException ex) {
386
                    }
387
                    this.spatialIndex.setValue(dataIndex);
388
                } catch (Exception ex) {
389
                    LOGGER.warn("Can't create spatial index", ex);
390
                }
391
            }
392
        }
393
        return this.spatialIndex.getValue();
394
    }
395

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

    
445
                            @Override
446
                            public FeatureReference next() {
447
                                Feature f = (Feature) it.next();
448
                                return f.getReference();
449
                            }
450
                        };
451
                    }
452
                };
453
                
454
            } catch(Exception ex) {
455
                return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR;
456
            }
457
        }
458
        final Iterator it = index.query(geom);
459
        if( it == null ) {
460
            return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR;
461
        }
462
        return new Iterable<FeatureReference>() {
463
            @Override
464
            public Iterator<FeatureReference> iterator() {
465
                return it;
466
            }
467
        };
468
    }
469

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

    
529
                    @Override
530
                    public Feature next() {
531
                        FeatureReference ref = (FeatureReference) it.next();
532
                        try {
533
                            return ref.getFeature();
534
                        } catch (DataException ex) {
535
                            return null;
536
                        }
537
                    }
538
                };
539
            }
540
        };
541
    }
542

    
543
    @Override
544
    public Feature findFirst(Expression filter) {
545
        try {
546
            return this.getFeatureStore().findFirst(filter);
547
        } catch (Exception ex) {
548
            return null;
549
        }
550
    }
551

    
552
}