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 @ 727
History | View | Annotate | Download (13.5 KB)
1 | 688 | jjdelcerro | /**
|
---|---|---|---|
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 | 725 | jjdelcerro | import java.util.Iterator; |
27 | 721 | jjdelcerro | import java.util.Map; |
28 | 725 | jjdelcerro | import org.apache.commons.collections.IteratorUtils; |
29 | 688 | jjdelcerro | import org.apache.commons.lang3.StringUtils; |
30 | 725 | jjdelcerro | import org.apache.commons.lang3.mutable.MutableObject; |
31 | import org.gvsig.expressionevaluator.Expression; |
||
32 | 727 | jjdelcerro | import org.gvsig.fmap.dal.DataStore; |
33 | 688 | jjdelcerro | import org.gvsig.fmap.dal.EditingNotification; |
34 | import org.gvsig.fmap.dal.EditingNotificationManager; |
||
35 | import org.gvsig.fmap.dal.exception.DataException; |
||
36 | import org.gvsig.fmap.dal.feature.EditableFeature; |
||
37 | import org.gvsig.fmap.dal.feature.Feature; |
||
38 | import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor; |
||
39 | import org.gvsig.fmap.dal.feature.FeatureReference; |
||
40 | import org.gvsig.fmap.dal.feature.FeatureStore; |
||
41 | 725 | jjdelcerro | import org.gvsig.fmap.dal.feature.FeatureStoreProviderFactory; |
42 | 688 | jjdelcerro | import org.gvsig.fmap.dal.feature.FeatureType; |
43 | import org.gvsig.fmap.dal.swing.DALSwingLocator; |
||
44 | import org.gvsig.fmap.geom.Geometry; |
||
45 | 725 | jjdelcerro | import org.gvsig.fmap.geom.GeometryLocator; |
46 | import org.gvsig.fmap.geom.GeometryManager; |
||
47 | import org.gvsig.fmap.geom.SpatialIndex; |
||
48 | 688 | jjdelcerro | import org.gvsig.fmap.geom.type.GeometryType; |
49 | import org.gvsig.tools.exception.BaseException; |
||
50 | 721 | jjdelcerro | import org.gvsig.tools.util.PropertiesSupportHelper; |
51 | 722 | jjdelcerro | import org.gvsig.tools.visitor.VisitCanceledException; |
52 | 688 | jjdelcerro | import org.gvsig.tools.visitor.Visitor; |
53 | import org.gvsig.topology.lib.api.CancelOperationException; |
||
54 | import org.gvsig.topology.lib.api.PerformOperationException; |
||
55 | import org.gvsig.topology.lib.api.TopologyDataSet; |
||
56 | import org.gvsig.topology.lib.api.TopologyLocator; |
||
57 | import org.gvsig.topology.lib.api.TopologyManager; |
||
58 | import org.json.JSONObject; |
||
59 | import org.gvsig.topology.lib.api.TopologyServices; |
||
60 | 725 | jjdelcerro | import org.slf4j.Logger; |
61 | import org.slf4j.LoggerFactory; |
||
62 | 688 | jjdelcerro | |
63 | /**
|
||
64 | *
|
||
65 | * @author jjdelcerro
|
||
66 | */
|
||
67 | @SuppressWarnings({"EqualsAndHashcode","UseSpecificCatch"}) |
||
68 | public class DefaultTopologyDataSet implements TopologyDataSet { |
||
69 | |||
70 | 725 | jjdelcerro | private final static Logger LOGGER = LoggerFactory.getLogger(DefaultTopologyDataSet.class); |
71 | |||
72 | 688 | jjdelcerro | private TopologyServices services;
|
73 | private String name; |
||
74 | 727 | jjdelcerro | private DataStore store;
|
75 | 688 | jjdelcerro | private boolean needFinishEditing; |
76 | private String fullName; |
||
77 | 721 | jjdelcerro | private PropertiesSupportHelper propertiesHelper;
|
78 | 725 | jjdelcerro | private MutableObject<SpatialIndex> spatialIndex = null; |
79 | |||
80 | 688 | jjdelcerro | public DefaultTopologyDataSet() {
|
81 | this.services = null; |
||
82 | this.name = null; |
||
83 | this.store = null; |
||
84 | this.needFinishEditing = false; |
||
85 | this.fullName = null; |
||
86 | 721 | jjdelcerro | this.propertiesHelper = new PropertiesSupportHelper(); |
87 | 688 | jjdelcerro | } |
88 | |||
89 | 727 | jjdelcerro | public DefaultTopologyDataSet(TopologyServices services, String name, DataStore store) { |
90 | 688 | jjdelcerro | this.services = services;
|
91 | this.name = name;
|
||
92 | this.store = store;
|
||
93 | this.needFinishEditing = false; |
||
94 | if( store!=null ) { |
||
95 | this.fullName = store.getFullName();
|
||
96 | } |
||
97 | } |
||
98 | |||
99 | 726 | jjdelcerro | public void restart() { |
100 | this.store = null; |
||
101 | this.spatialIndex = null; |
||
102 | } |
||
103 | |||
104 | 688 | jjdelcerro | @Override
|
105 | public boolean equals(Object obj) { |
||
106 | if( !(obj instanceof DefaultTopologyDataSet) ) { |
||
107 | return false; |
||
108 | } |
||
109 | DefaultTopologyDataSet other = (DefaultTopologyDataSet)obj; |
||
110 | if( this.store != other.store ) { |
||
111 | return false; |
||
112 | } |
||
113 | if( !StringUtils.equals(this.getName(), other.getName()) ) { |
||
114 | return false; |
||
115 | } |
||
116 | return true; |
||
117 | } |
||
118 | |||
119 | @Override
|
||
120 | public String getName() { |
||
121 | return this.name; |
||
122 | } |
||
123 | |||
124 | @Override
|
||
125 | public void setName(String name) { |
||
126 | this.name = name;
|
||
127 | } |
||
128 | |||
129 | @Override
|
||
130 | public String toString() { |
||
131 | try {
|
||
132 | 727 | jjdelcerro | FeatureAttributeDescriptor attr = this.getFeatureStore().getDefaultFeatureType().getDefaultGeometryAttribute();
|
133 | 688 | jjdelcerro | String geomType = attr.getGeomType().getName();
|
134 | return this.name + " ("+ geomType + ")"; |
||
135 | } catch(Exception ex) { |
||
136 | return this.name ; |
||
137 | } |
||
138 | } |
||
139 | |||
140 | @Override
|
||
141 | 727 | jjdelcerro | public DataStore getStore() {
|
142 | 688 | jjdelcerro | if (this.store == null) { |
143 | this.store = this.services.getFeatureStore(this); |
||
144 | } |
||
145 | return this.store; |
||
146 | } |
||
147 | |||
148 | @Override
|
||
149 | 727 | jjdelcerro | public FeatureStore getFeatureStore() {
|
150 | if (this.store == null) { |
||
151 | this.store = this.services.getFeatureStore(this); |
||
152 | } |
||
153 | return (FeatureStore) this.store; |
||
154 | } |
||
155 | |||
156 | @Override
|
||
157 | 688 | jjdelcerro | public long getSize() { |
158 | try {
|
||
159 | 727 | jjdelcerro | long size = this.getFeatureStore().getFeatureCount(); |
160 | 688 | jjdelcerro | return size;
|
161 | } catch (DataException ex) {
|
||
162 | // TODO: mensage al log
|
||
163 | return 0; |
||
164 | } |
||
165 | } |
||
166 | |||
167 | @Override
|
||
168 | public boolean isThisStore(FeatureStore store) { |
||
169 | if( store == null ) { |
||
170 | return false; |
||
171 | } |
||
172 | return StringUtils.equals(this.fullName, store.getFullName()); |
||
173 | } |
||
174 | |||
175 | @Override
|
||
176 | public int getGeometryType() { |
||
177 | try {
|
||
178 | 727 | jjdelcerro | FeatureStore theStore = this.getFeatureStore();
|
179 | 688 | jjdelcerro | FeatureType featureType = theStore.getDefaultFeatureType(); |
180 | FeatureAttributeDescriptor attr = featureType.getDefaultGeometryAttribute(); |
||
181 | GeometryType geomType = attr.getGeomType(); |
||
182 | return geomType.getType();
|
||
183 | } catch (Exception ex) { |
||
184 | return Geometry.TYPES.GEOMETRY;
|
||
185 | } |
||
186 | } |
||
187 | |||
188 | @Override
|
||
189 | 722 | jjdelcerro | public void accept(Visitor visitor) throws VisitCanceledException { |
190 | 727 | jjdelcerro | FeatureStore st = this.getFeatureStore();
|
191 | 688 | jjdelcerro | try {
|
192 | st.accept(visitor); |
||
193 | 722 | jjdelcerro | } catch(VisitCanceledException ex) {
|
194 | throw ex;
|
||
195 | } catch(BaseException ex) {
|
||
196 | 688 | jjdelcerro | throw new RuntimeException(ex); |
197 | } |
||
198 | } |
||
199 | |||
200 | @Override
|
||
201 | public void edit() throws DataException { |
||
202 | 727 | jjdelcerro | FeatureStore theStore = this.getFeatureStore();
|
203 | 688 | jjdelcerro | if (!theStore.isEditing()) {
|
204 | theStore.edit(); |
||
205 | this.needFinishEditing = true; |
||
206 | } |
||
207 | } |
||
208 | |||
209 | @Override
|
||
210 | public void finishEditing() throws DataException { |
||
211 | if (this.needFinishEditing) { |
||
212 | 727 | jjdelcerro | this.getFeatureStore().finishEditing();
|
213 | 688 | jjdelcerro | } |
214 | } |
||
215 | |||
216 | @Override
|
||
217 | public EditableFeature createNewFeature() throws DataException { |
||
218 | 727 | jjdelcerro | EditableFeature f = this.getFeatureStore().createNewFeature();
|
219 | 688 | jjdelcerro | return f;
|
220 | } |
||
221 | |||
222 | public void perform( |
||
223 | String operation,
|
||
224 | Feature feature |
||
225 | ) throws DataException {
|
||
226 | this.edit();
|
||
227 | |||
228 | EditingNotificationManager editingNotificationManager |
||
229 | = DALSwingLocator.getEditingNotificationManager(); |
||
230 | 727 | jjdelcerro | FeatureStore theStore = this.getFeatureStore();
|
231 | 688 | jjdelcerro | |
232 | EditingNotification notification |
||
233 | = editingNotificationManager.notifyObservers(this, // source |
||
234 | operation, // type
|
||
235 | null,// document |
||
236 | null,// layer |
||
237 | theStore,// store
|
||
238 | feature// feature
|
||
239 | ); |
||
240 | |||
241 | if (notification.isCanceled()) {
|
||
242 | String msg = String.format( |
||
243 | "Can't insert feature into %1$s, canceled by some observer.",
|
||
244 | this.getName());
|
||
245 | throw new CancelOperationException(msg); |
||
246 | } |
||
247 | |||
248 | String after = null; |
||
249 | if( operation.equalsIgnoreCase(EditingNotification.BEFORE_REMOVE_FEATURE) ) {
|
||
250 | theStore.delete(feature); |
||
251 | after = EditingNotification.AFTER_REMOVE_FEATURE; |
||
252 | |||
253 | } else {
|
||
254 | if (notification.shouldValidateTheFeature()) {
|
||
255 | if (!editingNotificationManager.validateFeature(feature)) {
|
||
256 | String msg = String.format("%1$s is not valid", feature.toString()); |
||
257 | throw new PerformOperationException(msg); |
||
258 | } |
||
259 | } |
||
260 | switch(operation) {
|
||
261 | case EditingNotification.BEFORE_UPDATE_FEATURE:
|
||
262 | theStore.update((EditableFeature) feature); |
||
263 | after = EditingNotification.AFTER_UPDATE_FEATURE; |
||
264 | break;
|
||
265 | |||
266 | case EditingNotification.BEFORE_INSERT_FEATURE:
|
||
267 | theStore.insert((EditableFeature) feature); |
||
268 | after = EditingNotification.AFTER_INSERT_FEATURE; |
||
269 | break;
|
||
270 | } |
||
271 | } |
||
272 | |||
273 | editingNotificationManager.notifyObservers(this,
|
||
274 | after, null, null, |
||
275 | theStore, feature); |
||
276 | |||
277 | } |
||
278 | |||
279 | @Override
|
||
280 | public void insert(final EditableFeature feature) throws DataException { |
||
281 | perform( |
||
282 | EditingNotification.BEFORE_INSERT_FEATURE, |
||
283 | feature |
||
284 | ); |
||
285 | } |
||
286 | |||
287 | @Override
|
||
288 | public void update(final EditableFeature feature) throws DataException { |
||
289 | perform( |
||
290 | EditingNotification.BEFORE_UPDATE_FEATURE, |
||
291 | feature |
||
292 | ); |
||
293 | } |
||
294 | |||
295 | @Override
|
||
296 | public void delete(final Feature feature) throws DataException { |
||
297 | perform( |
||
298 | EditingNotification.BEFORE_REMOVE_FEATURE, |
||
299 | feature |
||
300 | ); |
||
301 | } |
||
302 | |||
303 | @Override
|
||
304 | public void delete(final FeatureReference feature) throws DataException { |
||
305 | perform( |
||
306 | EditingNotification.BEFORE_REMOVE_FEATURE, |
||
307 | feature.getFeature() |
||
308 | ); |
||
309 | } |
||
310 | |||
311 | @Override
|
||
312 | public JSONObject toJSON() {
|
||
313 | JSONObject jsonDataSet = new JSONObject();
|
||
314 | jsonDataSet.put("name", this.name); |
||
315 | jsonDataSet.put("fullName", this.fullName); |
||
316 | |||
317 | return jsonDataSet;
|
||
318 | } |
||
319 | |||
320 | @Override
|
||
321 | public void fromJSON(String json) { |
||
322 | this.fromJSON(new JSONObject(json)); |
||
323 | } |
||
324 | |||
325 | @Override
|
||
326 | public void fromJSON(JSONObject json) { |
||
327 | TopologyManager manager = TopologyLocator.getTopologyManager(); |
||
328 | this.name = json.getString("name"); |
||
329 | this.fullName = null; |
||
330 | if( json.has("fullName") ) { |
||
331 | this.fullName = json.getString("fullName"); |
||
332 | } |
||
333 | this.store = null; |
||
334 | this.needFinishEditing = false; |
||
335 | this.services = manager.getDefaultServices();
|
||
336 | } |
||
337 | |||
338 | 721 | jjdelcerro | @Override
|
339 | public Object getProperty(String string) { |
||
340 | return this.propertiesHelper.getProperty(name); |
||
341 | } |
||
342 | |||
343 | @Override
|
||
344 | public void setProperty(String string, Object o) { |
||
345 | this.propertiesHelper.setProperty(name, o);
|
||
346 | } |
||
347 | |||
348 | @Override
|
||
349 | public Map<String, Object> getProperties() { |
||
350 | return this.propertiesHelper.getProperties(); |
||
351 | } |
||
352 | |||
353 | 725 | jjdelcerro | public SpatialIndex getSpatialIndex() {
|
354 | if( this.spatialIndex == null ) { |
||
355 | this.spatialIndex = new MutableObject<>(); |
||
356 | 727 | jjdelcerro | FeatureStore theStore = this.getFeatureStore();
|
357 | 725 | jjdelcerro | FeatureStoreProviderFactory storeFactory = (FeatureStoreProviderFactory) theStore.getProviderFactory(); |
358 | if( storeFactory.useLocalIndexesCanImprovePerformance()==FeatureStoreProviderFactory.YES ) {
|
||
359 | try {
|
||
360 | GeometryManager geomManager = GeometryLocator.getGeometryManager(); |
||
361 | final SpatialIndex geomIndex = geomManager.createSpatialIndex(
|
||
362 | GeometryManager.SPATIALINDEX_DEFAULT_QUADTREE, |
||
363 | null
|
||
364 | ); |
||
365 | final SpatialIndex dataIndex = theStore.wrapSpatialIndex(geomIndex);
|
||
366 | try {
|
||
367 | store.accept(new Visitor() {
|
||
368 | @Override
|
||
369 | public void visit(Object o) throws VisitCanceledException, BaseException { |
||
370 | Feature f = (Feature) o; |
||
371 | Geometry geom = f.getDefaultGeometry(); |
||
372 | if (geom != null) { |
||
373 | dataIndex.insert(geom, f); |
||
374 | } |
||
375 | } |
||
376 | }); |
||
377 | } catch (VisitCanceledException ex) {
|
||
378 | } |
||
379 | this.spatialIndex.setValue(dataIndex);
|
||
380 | } catch (Exception ex) { |
||
381 | LOGGER.warn("Can't create spatial index", ex);
|
||
382 | } |
||
383 | } |
||
384 | } |
||
385 | return this.spatialIndex.getValue(); |
||
386 | } |
||
387 | |||
388 | public Iterable<FeatureReference> query(Geometry geom) { |
||
389 | SpatialIndex index = this.getSpatialIndex();
|
||
390 | if( index == null ) { |
||
391 | return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR; |
||
392 | } |
||
393 | final Iterator it = index.query(geom); |
||
394 | if( it == null ) { |
||
395 | return (Iterable<FeatureReference>) IteratorUtils.EMPTY_ITERATOR; |
||
396 | } |
||
397 | return new Iterable<FeatureReference>() { |
||
398 | @Override
|
||
399 | public Iterator<FeatureReference> iterator() { |
||
400 | return it;
|
||
401 | } |
||
402 | }; |
||
403 | } |
||
404 | |||
405 | @Override
|
||
406 | public Feature findFirst(Expression filter) { |
||
407 | try {
|
||
408 | 727 | jjdelcerro | return this.getFeatureStore().findFirst(filter); |
409 | 725 | jjdelcerro | } catch (Exception ex) { |
410 | return null; |
||
411 | } |
||
412 | } |
||
413 | |||
414 | 688 | jjdelcerro | } |