X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=gis%2Fruntime%2Forg.argeo.gis.geotools%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fgeotools%2Fjcr%2FGeoJcrIndex.java;h=b9281b8229d1c9e19d1df22ebc1ea62e46fd4773;hb=c3be9f8db8a79e159d6a057758dfc7f3580efc2d;hp=2f62c8bf78cb344fc3a091cd94713f1b3f89934e;hpb=477f38e7085ce32c6f09e062cac90f7ba8769698;p=lgpl%2Fargeo-commons.git diff --git a/gis/runtime/org.argeo.gis.geotools/src/main/java/org/argeo/geotools/jcr/GeoJcrIndex.java b/gis/runtime/org.argeo.gis.geotools/src/main/java/org/argeo/geotools/jcr/GeoJcrIndex.java index 2f62c8bf7..b9281b822 100644 --- a/gis/runtime/org.argeo.gis.geotools/src/main/java/org/argeo/geotools/jcr/GeoJcrIndex.java +++ b/gis/runtime/org.argeo.gis.geotools/src/main/java/org/argeo/geotools/jcr/GeoJcrIndex.java @@ -1,9 +1,13 @@ package org.argeo.geotools.jcr; import java.io.IOException; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; import javax.jcr.Node; import javax.jcr.Property; @@ -12,6 +16,7 @@ import javax.jcr.Session; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; import javax.jcr.observation.EventListener; +import javax.jcr.observation.ObservationManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -21,7 +26,6 @@ import org.argeo.jcr.JcrUtils; import org.argeo.jcr.gis.GisNames; import org.argeo.jcr.gis.GisTypes; import org.argeo.jts.jcr.JtsJcrUtils; -import org.argeo.security.SystemExecutionService; import org.geotools.data.DataStore; import org.geotools.data.DefaultTransaction; import org.geotools.data.FeatureStore; @@ -31,117 +35,129 @@ import org.geotools.feature.FeatureCollections; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.filter.FilterFactoryImpl; +import org.geotools.referencing.CRS; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.FilterFactory2; import org.opengis.filter.identity.FeatureId; +import org.opengis.referencing.FactoryException; +import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; -public class GeoJcrIndex implements EventListener { - final static String GEOJCR_INDEX = "GEOJCR_INDEX"; +/** Index JCR nodes containing or referencing GIS data. */ +public class GeoJcrIndex implements EventListener, GisNames, GisTypes { // PostGIS convention final static String DEFAULT_GEOM_NAME = "the_geom"; private final static Log log = LogFactory.getLog(GeoJcrIndex.class); - public static SimpleFeatureType getWorkspaceGeoIndex(String workspaceName) { - SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); - builder.setNamespaceURI(GisNames.GIS_NAMESPACE); - builder.setName(workspaceName.toUpperCase() + "_" + GEOJCR_INDEX); - - builder.setDefaultGeometry(JcrUtils.normalize(GisNames.GIS_BBOX)); - builder.add(JcrUtils.normalize(GisNames.GIS_BBOX), Polygon.class); - builder.add(JcrUtils.normalize(GisNames.GIS_CENTROID), Point.class); - - builder.add(JcrUtils.normalize(Property.JCR_UUID), String.class); - builder.add(JcrUtils.normalize(Property.JCR_PATH), String.class); - builder.add(JcrUtils.normalize(Property.JCR_PRIMARY_TYPE), String.class); - // mix:lastModified - builder.add(JcrUtils.normalize(Property.JCR_LAST_MODIFIED), Date.class); - builder.add(JcrUtils.normalize(Property.JCR_LAST_MODIFIED_BY), - String.class); - - return builder.buildFeatureType(); - } - private DataStore dataStore; private Session session; - private SystemExecutionService systemExecutionService; + private Executor systemExecutionService; + + private String crs = "EPSG:4326"; + + /** The key is the workspace */ + private Map> geoJcrIndexes = Collections + .synchronizedMap(new HashMap>()); // TODO: use common factory finder? private FilterFactory2 ff = new FilterFactoryImpl(); + /** Expects to execute with system authentication */ public void init() { - - systemExecutionService.executeAsSystem(new Runnable() { - public void run() { - try { - session.getWorkspace() - .getObservationManager() - .addEventListener(GeoJcrIndex.this, - Event.NODE_ADDED | Event.NODE_REMOVED, "/", - true, null, - new String[] { GisTypes.GIS_INDEXED }, - false); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot initialize GeoJcr index", - e); + if (systemExecutionService != null)// legacy + systemExecutionService.execute(new Runnable() { + public void run() { + initGeoJcrIndex(); } + }); + else + initGeoJcrIndex(); + } - } - }); + protected void initGeoJcrIndex() { + try { + // create GIS schema + SimpleFeatureType indexType = getWorkspaceGeoJcrIndexType(session + .getWorkspace().getName()); + GeoToolsUtils.createSchemaIfNeeded(dataStore, indexType); + + // register JCR listeners + ObservationManager om = session.getWorkspace() + .getObservationManager(); + om.addEventListener(this, Event.NODE_ADDED | Event.NODE_REMOVED, + "/", true, null, null, false); + + // FIXME: use a different listener for properties since it resets + // the filter + // om.addEventListener(this, Event.PROPERTY_CHANGED, "/", + // true, null, new String[] { GIS_LOCATED }, false); + + } catch (RepositoryException e) { + throw new ArgeoException("Cannot initialize GeoJcr index", e); + } } public void dispose() { } - public void onEvent(EventIterator events) { - SimpleFeatureType indexType = getWorkspaceGeoIndex(session - .getWorkspace().getName()); - GeoToolsUtils.createSchemaIfNeeded(dataStore, indexType); - FeatureStore geoJcrIndex = GeoToolsUtils - .getFeatureStore(dataStore, indexType.getName()); - - FeatureCollection toAdd = FeatureCollections + public void onEvent(final EventIterator events) { + final FeatureCollection toAdd = FeatureCollections .newCollection(); - Set toRemove = new HashSet(); - while (events.hasNext()) { - Event event = events.nextEvent(); - try { - Integer eventType = event.getType(); - if (Event.NODE_ADDED == eventType) { - Node node = session.getNodeByIdentifier(event - .getIdentifier()); - if (node.isNodeType(GisTypes.GIS_LOCATED)) { - SimpleFeature feature = mapNodeToFeature(node, - indexType); - toAdd.add(feature); + final Set toRemove = new HashSet(); + + // execute with system authentication so that JCR can be read + systemExecutionService.execute(new Runnable() { + public void run() { + while (events.hasNext()) { + Event event = events.nextEvent(); + try { + Integer eventType = event.getType(); + if (Event.NODE_ADDED == eventType) { + Node node = session.getNodeByIdentifier(event + .getIdentifier()); + if (node.isNodeType(GIS_INDEXED)) { + SimpleFeature feature = mapNodeToFeature(node, + getGeoJcrIndex().getSchema()); + toAdd.add(feature); + } + } else if (Event.NODE_REMOVED == eventType) { + // we have no way to check whether the node was + // actually + // geoindexed without querying the index, this is + // therefore + // more optimal to create a filter with all ideas + // and apply + // a remove later on + String id = event.getIdentifier(); + toRemove.add(ff.featureId(id)); + } else if (Event.PROPERTY_CHANGED == eventType) { + // TODO: monitor changes to SRS, BBOX AND CENTROID + } + } catch (Exception e) { + log.error("Cannot process event " + event, e); } - } else if (Event.NODE_REMOVED == eventType) { - String id = event.getIdentifier(); - toRemove.add(ff.featureId(id)); } - } catch (Exception e) { - log.error("Cannot process event " + event, e); } - } + }); - // persist - // TODO: this may be more optimal to persist in one single transaction, - // but we will loose modifications on all nodes if one fails + // TODO: this may be more optimal to persist in one single + // transaction, + // but we will loose modifications on all nodes if a single one + // fails try { Transaction transaction = new DefaultTransaction(); - geoJcrIndex.setTransaction(transaction); + getGeoJcrIndex().setTransaction(transaction); try { // points - geoJcrIndex.addFeatures(toAdd); + getGeoJcrIndex().addFeatures(toAdd); if (toRemove.size() != 0) - geoJcrIndex.removeFeatures(ff.id(toRemove)); + getGeoJcrIndex().removeFeatures(ff.id(toRemove)); transaction.commit(); } catch (Exception e) { transaction.rollback(); @@ -156,52 +172,86 @@ public class GeoJcrIndex implements EventListener { } } + protected FeatureStore getGeoJcrIndex() { + String workspaceName = session.getWorkspace().getName(); + if (!geoJcrIndexes.containsKey(workspaceName)) { + SimpleFeatureType indexType = getWorkspaceGeoJcrIndexType(workspaceName); + FeatureStore geoIndex = GeoToolsUtils + .getFeatureStore(dataStore, indexType.getName()); + geoJcrIndexes.put(workspaceName, geoIndex); + } + return geoJcrIndexes.get(workspaceName); + } + + protected SimpleFeatureType getWorkspaceGeoJcrIndexType(String workspaceName) { + + SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); + builder.setNamespaceURI(GIS_NAMESPACE); + builder.setName(workspaceName + "_geojcr_index"); + try { + builder.setCRS(CRS.decode(crs)); + } catch (Exception e) { + throw new ArgeoException("Cannot set CRS " + crs, e); + } + + builder.setDefaultGeometry(JcrUtils.normalize(GIS_BBOX)); + builder.add(JcrUtils.normalize(GIS_BBOX), Polygon.class); + builder.add(JcrUtils.normalize(GIS_CENTROID), Point.class); + + builder.add(JcrUtils.normalize("jcr:uuid"), String.class); + builder.add(JcrUtils.normalize("jcr:path"), String.class); + builder.add(JcrUtils.normalize("jcr:primaryType"), String.class); + // mix:lastModified + builder.add(JcrUtils.normalize("jcr:lastModified"), Date.class); + builder.add(JcrUtils.normalize("jcr:lastModifiedBy"), String.class); + + return builder.buildFeatureType(); + } + protected SimpleFeature mapNodeToFeature(Node node, SimpleFeatureType type) { try { SimpleFeatureBuilder builder = new SimpleFeatureBuilder(type); Node locatedNode; - if (node.isNodeType(GisTypes.GIS_LOCATED)) { + if (node.isNodeType(GIS_LOCATED)) { locatedNode = node; - } else if (node.isNodeType(GisTypes.GIS_INDEXED)) { - locatedNode = findLocatedparent(node); + } else if (node.isNodeType(GIS_INDEXED)) { + locatedNode = findLocatedParent(node); } else { throw new ArgeoException("Unsupported node " + node); } // TODO: reproject to the feature store SRS Polygon bbox = (Polygon) JtsJcrUtils.readWkb(locatedNode - .getProperty(GisNames.GIS_BBOX)); - builder.set(JcrUtils.normalize(GisNames.GIS_BBOX), bbox); - Polygon centroid = (Polygon) JtsJcrUtils.readWkb(locatedNode - .getProperty(GisNames.GIS_CENTROID)); - builder.set(JcrUtils.normalize(GisNames.GIS_CENTROID), centroid); - - builder.set(JcrUtils.normalize(Property.JCR_UUID), - node.getIdentifier()); - builder.set(JcrUtils.normalize(Property.JCR_PATH), node.getPath()); - builder.set(JcrUtils.normalize(Property.JCR_PRIMARY_TYPE), node + .getProperty(GIS_BBOX)); + builder.set(JcrUtils.normalize(GIS_BBOX), bbox); + Point centroid = (Point) JtsJcrUtils.readWkb(locatedNode + .getProperty(GIS_CENTROID)); + builder.set(JcrUtils.normalize(GIS_CENTROID), centroid); + + builder.set(JcrUtils.normalize("jcr:uuid"), node.getIdentifier()); + builder.set(JcrUtils.normalize("jcr:path"), node.getPath()); + builder.set(JcrUtils.normalize("jcr:primaryType"), node .getPrimaryNodeType().getName()); if (node.hasProperty(Property.JCR_LAST_MODIFIED)) - builder.set(JcrUtils.normalize(Property.JCR_LAST_MODIFIED), - node.getProperty(Property.JCR_LAST_MODIFIED).getDate() - .getTime()); + builder.set(JcrUtils.normalize("jcr:lastModified"), node + .getProperty(Property.JCR_LAST_MODIFIED).getDate() + .getTime()); if (node.hasProperty(Property.JCR_LAST_MODIFIED_BY)) - builder.set(JcrUtils.normalize(Property.JCR_LAST_MODIFIED_BY), - node.getProperty(Property.JCR_LAST_MODIFIED_BY) - .getString()); + builder.set(JcrUtils.normalize("jcr:lastModifiedBy"), node + .getProperty(Property.JCR_LAST_MODIFIED_BY).getString()); return builder.buildFeature(node.getIdentifier()); } catch (RepositoryException e) { throw new ArgeoException("Cannot map " + node + " to " + type, e); } } - protected Node findLocatedparent(Node child) { + protected Node findLocatedParent(Node child) { try { - if (child.getParent().isNodeType(GisTypes.GIS_LOCATED)) + if (child.getParent().isNodeType(GIS_LOCATED)) return child.getParent(); else - return findLocatedparent(child.getParent()); + return findLocatedParent(child.getParent()); } catch (Exception e) { // also if child is root node throw new ArgeoException("Cannot find located parent", e); @@ -257,8 +307,7 @@ public class GeoJcrIndex implements EventListener { this.session = session; } - public void setSystemExecutionService( - SystemExecutionService systemExecutionService) { + public void setSystemExecutionService(Executor systemExecutionService) { this.systemExecutionService = systemExecutionService; }