]> git.argeo.org Git - lgpl/argeo-commons.git/blob - gis/runtime/org.argeo.gis.geotools/src/main/java/org/argeo/geotools/jcr/GeoJcrIndex.java
GIS does not expose perspectives and views
[lgpl/argeo-commons.git] / gis / runtime / org.argeo.gis.geotools / src / main / java / org / argeo / geotools / jcr / GeoJcrIndex.java
1 package org.argeo.geotools.jcr;
2
3 import java.io.IOException;
4 import java.util.Date;
5 import java.util.HashSet;
6 import java.util.Set;
7
8 import javax.jcr.Node;
9 import javax.jcr.Property;
10 import javax.jcr.RepositoryException;
11 import javax.jcr.Session;
12 import javax.jcr.observation.Event;
13 import javax.jcr.observation.EventIterator;
14 import javax.jcr.observation.EventListener;
15
16 import org.apache.commons.logging.Log;
17 import org.apache.commons.logging.LogFactory;
18 import org.argeo.ArgeoException;
19 import org.argeo.geotools.GeoToolsUtils;
20 import org.argeo.jcr.JcrUtils;
21 import org.argeo.jcr.gis.GisNames;
22 import org.argeo.jcr.gis.GisTypes;
23 import org.argeo.jts.jcr.JtsJcrUtils;
24 import org.argeo.security.SystemExecutionService;
25 import org.geotools.data.DataStore;
26 import org.geotools.data.DefaultTransaction;
27 import org.geotools.data.FeatureStore;
28 import org.geotools.data.Transaction;
29 import org.geotools.feature.FeatureCollection;
30 import org.geotools.feature.FeatureCollections;
31 import org.geotools.feature.simple.SimpleFeatureBuilder;
32 import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
33 import org.geotools.filter.FilterFactoryImpl;
34 import org.opengis.feature.simple.SimpleFeature;
35 import org.opengis.feature.simple.SimpleFeatureType;
36 import org.opengis.filter.FilterFactory2;
37 import org.opengis.filter.identity.FeatureId;
38 import org.opengis.referencing.crs.CoordinateReferenceSystem;
39
40 import com.vividsolutions.jts.geom.Geometry;
41 import com.vividsolutions.jts.geom.Point;
42 import com.vividsolutions.jts.geom.Polygon;
43
44 public class GeoJcrIndex implements EventListener {
45 final static String GEOJCR_INDEX = "GEOJCR_INDEX";
46 // PostGIS convention
47 final static String DEFAULT_GEOM_NAME = "the_geom";
48
49 private final static Log log = LogFactory.getLog(GeoJcrIndex.class);
50
51 public static SimpleFeatureType getWorkspaceGeoIndex(String workspaceName) {
52 SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
53 builder.setNamespaceURI(GisNames.GIS_NAMESPACE);
54 builder.setName(workspaceName.toUpperCase() + "_" + GEOJCR_INDEX);
55
56 builder.setDefaultGeometry(JcrUtils.normalize(GisNames.GIS_BBOX));
57 builder.add(JcrUtils.normalize(GisNames.GIS_BBOX), Polygon.class);
58 builder.add(JcrUtils.normalize(GisNames.GIS_CENTROID), Point.class);
59
60 builder.add(JcrUtils.normalize(Property.JCR_UUID), String.class);
61 builder.add(JcrUtils.normalize(Property.JCR_PATH), String.class);
62 builder.add(JcrUtils.normalize(Property.JCR_PRIMARY_TYPE), String.class);
63 // mix:lastModified
64 builder.add(JcrUtils.normalize(Property.JCR_LAST_MODIFIED), Date.class);
65 builder.add(JcrUtils.normalize(Property.JCR_LAST_MODIFIED_BY),
66 String.class);
67
68 return builder.buildFeatureType();
69 }
70
71 private DataStore dataStore;
72 private Session session;
73 private SystemExecutionService systemExecutionService;
74
75 // TODO: use common factory finder?
76 private FilterFactory2 ff = new FilterFactoryImpl();
77
78 public void init() {
79
80 systemExecutionService.executeAsSystem(new Runnable() {
81 public void run() {
82 try {
83 session.getWorkspace()
84 .getObservationManager()
85 .addEventListener(GeoJcrIndex.this,
86 Event.NODE_ADDED | Event.NODE_REMOVED, "/",
87 true, null,
88 new String[] { GisTypes.GIS_INDEXED },
89 false);
90 } catch (RepositoryException e) {
91 throw new ArgeoException("Cannot initialize GeoJcr index",
92 e);
93 }
94
95 }
96 });
97 }
98
99 public void dispose() {
100 }
101
102 public void onEvent(EventIterator events) {
103 SimpleFeatureType indexType = getWorkspaceGeoIndex(session
104 .getWorkspace().getName());
105 GeoToolsUtils.createSchemaIfNeeded(dataStore, indexType);
106 FeatureStore<SimpleFeatureType, SimpleFeature> geoJcrIndex = GeoToolsUtils
107 .getFeatureStore(dataStore, indexType.getName());
108
109 FeatureCollection<SimpleFeatureType, SimpleFeature> toAdd = FeatureCollections
110 .newCollection();
111 Set<FeatureId> toRemove = new HashSet<FeatureId>();
112 while (events.hasNext()) {
113 Event event = events.nextEvent();
114 try {
115 Integer eventType = event.getType();
116 if (Event.NODE_ADDED == eventType) {
117 Node node = session.getNodeByIdentifier(event
118 .getIdentifier());
119 if (node.isNodeType(GisTypes.GIS_LOCATED)) {
120 SimpleFeature feature = mapNodeToFeature(node,
121 indexType);
122 toAdd.add(feature);
123 }
124 } else if (Event.NODE_REMOVED == eventType) {
125 String id = event.getIdentifier();
126 toRemove.add(ff.featureId(id));
127 }
128 } catch (Exception e) {
129 log.error("Cannot process event " + event, e);
130 }
131 }
132
133 // persist
134 // TODO: this may be more optimal to persist in one single transaction,
135 // but we will loose modifications on all nodes if one fails
136 try {
137 Transaction transaction = new DefaultTransaction();
138 geoJcrIndex.setTransaction(transaction);
139 try {
140 // points
141 geoJcrIndex.addFeatures(toAdd);
142 if (toRemove.size() != 0)
143 geoJcrIndex.removeFeatures(ff.id(toRemove));
144 transaction.commit();
145 } catch (Exception e) {
146 transaction.rollback();
147 throw new ArgeoException("Cannot persist changes", e);
148 } finally {
149 transaction.close();
150 }
151 } catch (ArgeoException e) {
152 throw e;
153 } catch (IOException e) {
154 throw new ArgeoException("Unexpected issue with the transaction", e);
155 }
156 }
157
158 protected SimpleFeature mapNodeToFeature(Node node, SimpleFeatureType type) {
159 try {
160 SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type);
161
162 Node locatedNode;
163 if (node.isNodeType(GisTypes.GIS_LOCATED)) {
164 locatedNode = node;
165 } else if (node.isNodeType(GisTypes.GIS_INDEXED)) {
166 locatedNode = findLocatedparent(node);
167 } else {
168 throw new ArgeoException("Unsupported node " + node);
169 }
170
171 // TODO: reproject to the feature store SRS
172 Polygon bbox = (Polygon) JtsJcrUtils.readWkb(locatedNode
173 .getProperty(GisNames.GIS_BBOX));
174 builder.set(JcrUtils.normalize(GisNames.GIS_BBOX), bbox);
175 Polygon centroid = (Polygon) JtsJcrUtils.readWkb(locatedNode
176 .getProperty(GisNames.GIS_CENTROID));
177 builder.set(JcrUtils.normalize(GisNames.GIS_CENTROID), centroid);
178
179 builder.set(JcrUtils.normalize(Property.JCR_UUID),
180 node.getIdentifier());
181 builder.set(JcrUtils.normalize(Property.JCR_PATH), node.getPath());
182 builder.set(JcrUtils.normalize(Property.JCR_PRIMARY_TYPE), node
183 .getPrimaryNodeType().getName());
184 if (node.hasProperty(Property.JCR_LAST_MODIFIED))
185 builder.set(JcrUtils.normalize(Property.JCR_LAST_MODIFIED),
186 node.getProperty(Property.JCR_LAST_MODIFIED).getDate()
187 .getTime());
188 if (node.hasProperty(Property.JCR_LAST_MODIFIED_BY))
189 builder.set(JcrUtils.normalize(Property.JCR_LAST_MODIFIED_BY),
190 node.getProperty(Property.JCR_LAST_MODIFIED_BY)
191 .getString());
192 return builder.buildFeature(node.getIdentifier());
193 } catch (RepositoryException e) {
194 throw new ArgeoException("Cannot map " + node + " to " + type, e);
195 }
196 }
197
198 protected Node findLocatedparent(Node child) {
199 try {
200 if (child.getParent().isNodeType(GisTypes.GIS_LOCATED))
201 return child.getParent();
202 else
203 return findLocatedparent(child.getParent());
204 } catch (Exception e) {
205 // also if child is root node
206 throw new ArgeoException("Cannot find located parent", e);
207 }
208 }
209
210 /** Returns the node as a point in the CRS of the related feature store. */
211 protected Geometry reproject(CoordinateReferenceSystem crs,
212 Geometry geometry, CoordinateReferenceSystem targetCrs) {
213 // transform if not same CRS
214 // FIXME: there is certainly a more standard way to reproject
215 if (!targetCrs.getIdentifiers().contains(crs.getName())) {
216 throw new ArgeoException("Reprojection not yet supported");
217 // MathTransform transform;
218 // try {
219 // transform = CRS.findMathTransform(nodeCrs, featureStoreCrs);
220 // if (geometry instanceof Point) {
221 // Point point = (Point) geometry;
222 // DirectPosition2D pos = new DirectPosition2D(nodeCrs,
223 // point.getX(), point.getY());
224 // DirectPosition targetPos = transform.transform(pos, null);
225 // return geometryFactory.createPoint(new Coordinate(targetPos
226 // .getCoordinate()[0], targetPos.getCoordinate()[1]));
227 // } else if (geometry instanceof Polygon) {
228 // Polygon polygon = (Polygon) geometry;
229 // List<Coordinate> coordinates = new ArrayList<Coordinate>();
230 // for (Coordinate coo : polygon.getExteriorRing()) {
231 // DirectPosition pos = new DirectPosition2D(nodeCrs,
232 // coo.x, coo.y);
233 // DirectPosition targetPos = transform.transform(pos,
234 // null);
235 // // coordinates.add(o)
236 // }
237 // LinearRing ring = geometryFactory
238 // .createLinearRing(coordinates
239 // .toArray(new Coordinate[coordinates.size()]));
240 // return geometryFactory.createPolygon(ring, null);
241 // }
242 // } catch (Exception e) {
243 // throw new ArgeoException("Cannot transform from " + nodeCrs
244 // + " to " + featureStoreCrs, e);
245 // }
246 } else {
247 return geometry;
248 }
249 }
250
251 public void setDataStore(DataStore dataStore) {
252 this.dataStore = dataStore;
253 }
254
255 public void setSession(Session session) {
256 this.session = session;
257 }
258
259 public void setSystemExecutionService(
260 SystemExecutionService systemExecutionService) {
261 this.systemExecutionService = systemExecutionService;
262 }
263
264 }