+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
- <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
- <classpathentry kind="src" path="src/main/java"/>
- <classpathentry kind="output" path="target/classes"/>
-</classpath>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
- <name>org.argeo.gis.geotools</name>
- <comment></comment>
- <projects>
- </projects>
- <buildSpec>
- <buildCommand>
- <name>org.eclipse.jdt.core.javabuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.ManifestBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- <buildCommand>
- <name>org.eclipse.pde.SchemaBuilder</name>
- <arguments>
- </arguments>
- </buildCommand>
- </buildSpec>
- <natures>
- <nature>org.eclipse.pde.PluginNature</nature>
- <nature>org.eclipse.jdt.core.javanature</nature>
- </natures>
-</projectDescription>
+++ /dev/null
-#Sun Feb 27 13:54:27 CET 2011
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
-org.eclipse.jdt.core.compiler.compliance=1.5
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.5
+++ /dev/null
-#Sun Feb 27 13:54:27 CET 2011
-eclipse.preferences.version=1
-pluginProject.extensions=false
-resolve.requirebundle=false
+++ /dev/null
-source.. = src/main/java/
-output.. = target/classes/
-bin.includes = META-INF/,\
- .
+++ /dev/null
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.argeo.commons.gis</groupId>
- <artifactId>runtime</artifactId>
- <version>0.3.4-SNAPSHOT</version>
- <relativePath>..</relativePath>
- </parent>
- <artifactId>org.argeo.gis.geotools</artifactId>
- <name>Commons GIS Geotools</name>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-source-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <version>${version.maven-bundle-plugin}</version>
- <configuration>
- <instructions>
- <Export-Package>org.argeo.geotools.*,org.argeo.jts.*</Export-Package>
- <Import-Package>org.argeo.jcr.gis,*</Import-Package>
- </instructions>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.argeo.maven.plugins</groupId>
- <artifactId>maven-argeo-osgi-plugin</artifactId>
- <version>${version.maven-argeo-osgi}</version>
- <executions>
- <execution>
- <id>check-osgi</id>
- <phase>test</phase>
- <goals>
- <goal>equinox</goal>
- </goals>
- <configuration>
- <onlyCheck>true</onlyCheck>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <!-- Commons -->
- <dependency>
- <groupId>org.argeo.commons.server</groupId>
- <artifactId>org.argeo.server.jcr</artifactId>
- <version>0.3.4-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.argeo.commons.security</groupId>
- <artifactId>org.argeo.security.core</artifactId>
- <version>0.3.4-SNAPSHOT</version>
- </dependency>
-
- <!-- Geotools, JTS, etc. -->
- <dependency>
- <groupId>org.argeo.dep.osgi</groupId>
- <artifactId>org.argeo.dep.osgi.geotools</artifactId>
- </dependency>
- <dependency>
- <groupId>org.argeo.dep.osgi</groupId>
- <artifactId>org.argeo.dep.osgi.geoapi</artifactId>
- </dependency>
- <dependency>
- <groupId>org.argeo.dep.osgi</groupId>
- <artifactId>org.argeo.dep.osgi.jts</artifactId>
- </dependency>
- <dependency>
- <groupId>org.jdom</groupId>
- <artifactId>com.springsource.org.jdom</artifactId>
- </dependency>
- <dependency>
- <groupId>org.jaxen</groupId>
- <artifactId>com.springsource.org.jaxen</artifactId>
- </dependency>
- <dependency>
- <groupId>org.argeo.dep.osgi</groupId>
- <artifactId>org.argeo.dep.osgi.jsr275</artifactId>
- </dependency>
- <dependency>
- <groupId>org.argeo.dep.osgi</groupId>
- <artifactId>org.argeo.dep.osgi.java3d</artifactId>
- </dependency>
- <!-- For EPSG database -->
- <dependency>
- <groupId>org.hsqldb</groupId>
- <artifactId>com.springsource.org.hsqldb</artifactId>
- </dependency>
- <!-- Apache Commons -->
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>com.springsource.org.apache.commons.beanutils</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>com.springsource.org.apache.commons.dbcp</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>com.springsource.org.apache.commons.lang</artifactId>
- </dependency>
- <!-- JAI -->
- <dependency>
- <groupId>javax.media.jai</groupId>
- <artifactId>com.springsource.javax.media.jai.core</artifactId>
- </dependency>
- <dependency>
- <groupId>javax.media.jai</groupId>
- <artifactId>com.springsource.javax.media.jai.codec</artifactId>
- </dependency>
- <dependency>
- <groupId>org.argeo.dep.osgi</groupId>
- <artifactId>org.argeo.dep.osgi.jai.imageio</artifactId>
- </dependency>
-
- <!-- Logging -->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>com.springsource.slf4j.org.apache.commons.logging
- </artifactId>
- </dependency>
-
- <!-- OSGi -->
- <dependency>
- <groupId>org.eclipse.osgi</groupId>
- <artifactId>org.eclipse.osgi</artifactId>
- </dependency>
-
- <!-- OSGi test -->
- <dependency>
- <groupId>org.argeo.commons.osgi</groupId>
- <artifactId>org.argeo.osgi.boot</artifactId>
- <version>0.3.4-SNAPSHOT</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.argeo.commons.basic</groupId>
- <artifactId>org.argeo.basic.dep.log4j</artifactId>
- <version>0.3.4-SNAPSHOT</version>
- <type>pom</type>
- <scope>test</scope>
- </dependency>
- </dependencies>
-</project>
+++ /dev/null
-package org.argeo.geotools;
-
-import org.geotools.data.DataStore;
-
-/** Constants used by the GeoTools utilities. */
-public interface GeoToolsConstants {
- /**
- * Property used to bastract the identification of some objects (typically
- * {@link DataStore}. Especially useful as service property in OSGi.
- */
- public final static String ALIAS_KEY = "alias";
-}
+++ /dev/null
-package org.argeo.geotools;
-
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-import org.geotools.data.DataStore;
-import org.geotools.data.FeatureSource;
-import org.geotools.data.FeatureStore;
-import org.geotools.feature.FeatureIterator;
-import org.geotools.filter.FilterFactoryImpl;
-import org.opengis.feature.simple.SimpleFeature;
-import org.opengis.feature.simple.SimpleFeatureType;
-import org.opengis.feature.type.Name;
-import org.opengis.filter.Filter;
-import org.opengis.filter.FilterFactory2;
-import org.opengis.filter.identity.FeatureId;
-
-/** Utilities related to the GeoTools framework */
-public class GeoToolsUtils {
-
- private final static Log log = LogFactory.getLog(GeoToolsUtils.class);
-
- // TODO: use common factory finder?
- private static FilterFactory2 filterFactory = new FilterFactoryImpl();
-
- /** Opens a read/write feature store */
- public static FeatureStore<SimpleFeatureType, SimpleFeature> getFeatureStore(
- DataStore dataStore, Name name) {
- FeatureSource<SimpleFeatureType, SimpleFeature> featureSource;
- try {
- featureSource = dataStore.getFeatureSource(name);
- } catch (IOException e) {
- throw new ArgeoException("Cannot open feature source " + name
- + " in data store " + dataStore, e);
- }
- if (!(featureSource instanceof FeatureStore)) {
- throw new ArgeoException("Feature source " + name
- + " is not writable.");
- }
- return (FeatureStore<SimpleFeatureType, SimpleFeature>) featureSource;
- }
-
- /** Creates the provided schema in the data store. */
- public static void createSchemaIfNeeded(DataStore dataStore,
- SimpleFeatureType featureType) {
- try {
- dataStore.getSchema(featureType.getName());
- } catch (IOException e) {
- // assume it does not exist
- try {
- dataStore.createSchema(featureType);
- } catch (IOException e1) {
- throw new ArgeoException("Cannot create schema " + featureType,
- e1);
- }
- }
- }
-
- public static FilterFactory2 ff() {
- return filterFactory;
- }
-
- public static SimpleFeature querySingleFeature(
- FeatureSource<SimpleFeatureType, SimpleFeature> featureSource,
- String featureId) {
- Set<FeatureId> ids = new HashSet<FeatureId>();
- ids.add(ff().featureId(featureId));
- Filter filter = ff().id(ids);
- FeatureIterator<SimpleFeature> it = null;
- try {
- it = featureSource.getFeatures(filter).features();
- if (!it.hasNext())
- return null;
- else {
- SimpleFeature feature = it.next();
- if (it.hasNext())
- log.warn("More than one feature for feature id "
- + featureId + " in feature source "
- + featureSource.getName());
- return feature;
- }
- } catch (Exception e) {
- throw new ArgeoException("Cannot extract single feature "
- + featureId + " from feature source "
- + featureSource.getName(), e);
- } finally {
- closeQuietly(it);
- }
- }
-
- public static void closeQuietly(FeatureIterator<?> featureIterator) {
- if (featureIterator != null)
- try {
- featureIterator.close();
- } catch (Exception e) {
- // silent
- }
- }
-}
+++ /dev/null
-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;
-import javax.jcr.RepositoryException;
-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;
-import org.argeo.ArgeoException;
-import org.argeo.geotools.GeoToolsUtils;
-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.geotools.data.DataStore;
-import org.geotools.data.DefaultTransaction;
-import org.geotools.data.FeatureStore;
-import org.geotools.data.Transaction;
-import org.geotools.feature.FeatureCollection;
-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.Point;
-import com.vividsolutions.jts.geom.Polygon;
-
-/** 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);
-
- private DataStore dataStore;
- private Session session;
- private Executor systemExecutionService;
-
- private String crs = "EPSG:4326";
-
- /** The key is the workspace */
- private Map<String, FeatureStore<SimpleFeatureType, SimpleFeature>> geoJcrIndexes = Collections
- .synchronizedMap(new HashMap<String, FeatureStore<SimpleFeatureType, SimpleFeature>>());
-
- // TODO: use common factory finder?
- private FilterFactory2 ff = new FilterFactoryImpl();
-
- /** Expects to execute with system authentication */
- public void init() {
- 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(final EventIterator events) {
- final FeatureCollection<SimpleFeatureType, SimpleFeature> toAdd = FeatureCollections
- .newCollection();
- final Set<FeatureId> toRemove = new HashSet<FeatureId>();
-
- // 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);
- }
- }
- }
- });
-
- // 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();
- getGeoJcrIndex().setTransaction(transaction);
- try {
- // points
- getGeoJcrIndex().addFeatures(toAdd);
- if (toRemove.size() != 0)
- getGeoJcrIndex().removeFeatures(ff.id(toRemove));
- transaction.commit();
- } catch (Exception e) {
- transaction.rollback();
- throw new ArgeoException("Cannot persist changes", e);
- } finally {
- transaction.close();
- }
- } catch (ArgeoException e) {
- throw e;
- } catch (IOException e) {
- throw new ArgeoException("Unexpected issue with the transaction", e);
- }
- }
-
- protected FeatureStore<SimpleFeatureType, SimpleFeature> getGeoJcrIndex() {
- String workspaceName = session.getWorkspace().getName();
- if (!geoJcrIndexes.containsKey(workspaceName)) {
- SimpleFeatureType indexType = getWorkspaceGeoJcrIndexType(workspaceName);
- FeatureStore<SimpleFeatureType, SimpleFeature> 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(GIS_LOCATED)) {
- locatedNode = 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(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("jcr:lastModified"), node
- .getProperty(Property.JCR_LAST_MODIFIED).getDate()
- .getTime());
- if (node.hasProperty(Property.JCR_LAST_MODIFIED_BY))
- 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) {
- try {
- if (child.getParent().isNodeType(GIS_LOCATED))
- return child.getParent();
- else
- return findLocatedParent(child.getParent());
- } catch (Exception e) {
- // also if child is root node
- throw new ArgeoException("Cannot find located parent", e);
- }
- }
-
- /** Returns the node as a point in the CRS of the related feature store. */
- protected Geometry reproject(CoordinateReferenceSystem crs,
- Geometry geometry, CoordinateReferenceSystem targetCrs) {
- // transform if not same CRS
- // FIXME: there is certainly a more standard way to reproject
- if (!targetCrs.getIdentifiers().contains(crs.getName())) {
- throw new ArgeoException("Reprojection not yet supported");
- // MathTransform transform;
- // try {
- // transform = CRS.findMathTransform(nodeCrs, featureStoreCrs);
- // if (geometry instanceof Point) {
- // Point point = (Point) geometry;
- // DirectPosition2D pos = new DirectPosition2D(nodeCrs,
- // point.getX(), point.getY());
- // DirectPosition targetPos = transform.transform(pos, null);
- // return geometryFactory.createPoint(new Coordinate(targetPos
- // .getCoordinate()[0], targetPos.getCoordinate()[1]));
- // } else if (geometry instanceof Polygon) {
- // Polygon polygon = (Polygon) geometry;
- // List<Coordinate> coordinates = new ArrayList<Coordinate>();
- // for (Coordinate coo : polygon.getExteriorRing()) {
- // DirectPosition pos = new DirectPosition2D(nodeCrs,
- // coo.x, coo.y);
- // DirectPosition targetPos = transform.transform(pos,
- // null);
- // // coordinates.add(o)
- // }
- // LinearRing ring = geometryFactory
- // .createLinearRing(coordinates
- // .toArray(new Coordinate[coordinates.size()]));
- // return geometryFactory.createPolygon(ring, null);
- // }
- // } catch (Exception e) {
- // throw new ArgeoException("Cannot transform from " + nodeCrs
- // + " to " + featureStoreCrs, e);
- // }
- } else {
- return geometry;
- }
- }
-
- public void setDataStore(DataStore dataStore) {
- this.dataStore = dataStore;
- }
-
- public void setSession(Session session) {
- this.session = session;
- }
-
- public void setSystemExecutionService(Executor systemExecutionService) {
- this.systemExecutionService = systemExecutionService;
- }
-
-}
+++ /dev/null
-package org.argeo.geotools.jcr;
-
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.Node;
-import javax.jcr.Session;
-
-import org.geotools.data.FeatureSource;
-import org.opengis.feature.simple.SimpleFeature;
-import org.opengis.feature.simple.SimpleFeatureType;
-
-/**
- * Maps datastore and feature sources with JCR nodes. It is meant to be
- * repository independent.
- */
-public interface GeoJcrMapper {
- public Map<String, List<FeatureSource<SimpleFeatureType, SimpleFeature>>> getPossibleFeatureSources();
-
- public Node getFeatureSourceNode(Session session, String dataStoreAlias,
- FeatureSource<SimpleFeatureType, SimpleFeature> featureSource);
-
- public Node getFeatureNode(Node featureSource, String featureId);
-
- public FeatureSource<SimpleFeatureType, SimpleFeature> getFeatureSource(
- Node node);
-
- public SimpleFeature getFeature(Node node);
-}
+++ /dev/null
-package org.argeo.geotools.jcr;
-
-import javax.jcr.Node;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-import org.argeo.jcr.gis.GisNames;
-import org.argeo.jcr.gis.GisTypes;
-import org.geotools.geometry.DirectPosition2D;
-import org.geotools.geometry.jts.JTS;
-import org.geotools.referencing.CRS;
-import org.opengis.geometry.DirectPosition;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.operation.MathTransform;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Geometry;
-import com.vividsolutions.jts.geom.GeometryFactory;
-import com.vividsolutions.jts.geom.Point;
-
-/** Utilities to map JCR from/to JTS and GeoTools */
-public class GeoJcrUtils {
- private final static Log log = LogFactory.getLog(GeoJcrUtils.class);
-
- /** Transforms a geometry node into position within its CRS */
- public static DirectPosition nodeToPosition(Node node) {
- try {
- if (node.isNodeType(GisTypes.GIS_POINT)) {
- CoordinateReferenceSystem crs = getCoordinateReferenceSystem(node);
- Point point = (Point) nodeToGeometry(node);
- return new DirectPosition2D(crs, point.getX(), point.getY());
- } else {
- throw new ArgeoException(node + " is not of a supported type");
- }
- } catch (Exception e) {
- throw new ArgeoException("Cannot extract position from " + node, e);
- }
- }
-
- /** Transforms a geometry node into a JTS geometry. */
- public static Geometry nodeToGeometry(Node node) {
- try {
- if (node.isNodeType(GisTypes.GIS_POINT)
- || node.isNodeType(GisTypes.GIS_COORDINATE)) {
- Coordinate coo;
- if (node.hasProperty(GisNames.GIS_Z))
- coo = new Coordinate(node.getProperty(GisNames.GIS_X)
- .getDouble(), node.getProperty(GisNames.GIS_Y)
- .getDouble(), node.getProperty(GisNames.GIS_Z)
- .getDouble());
- else
- coo = new Coordinate(node.getProperty(GisNames.GIS_X)
- .getDouble(), node.getProperty(GisNames.GIS_Y)
- .getDouble());
-
- // TODO: use factory finder
- // GeometryFactory geometryFactory =
- // JTSFactoryFinder.getGeometryFactory(null);
- GeometryFactory geometryFactory = new GeometryFactory();
- return geometryFactory.createPoint(coo);
- } else {
- throw new ArgeoException(node + " is not of a supported type");
- }
- } catch (Exception e) {
- throw new ArgeoException("Cannot map " + node + " to a geometry", e);
- }
- }
-
- /** Reads and interpret the coordinate reference system from a node. */
- public static CoordinateReferenceSystem getCoordinateReferenceSystem(
- Node node) {
- try {
- if (!node.isNodeType(GisTypes.GIS_LOCATED))
- throw new ArgeoException(node + " is not of type "
- + GisTypes.GIS_LOCATED);
- // Coordinate reference system
- String srs = node.getProperty(GisNames.GIS_SRS).getString();
- CoordinateReferenceSystem crs;
- try {
- // first, try to decode an EPSG code
- crs = CRS.decode(srs);
- } catch (Exception e) {
- // if it fails, try a WKT
- try {
- crs = CRS.parseWKT(srs);
- } catch (Exception e1) {
- // if it fails as well, log the error
- log.error("Cannot parse WKT " + srs, e1);
- // and then the previous error (probably more relevant)
- throw e;
- }
- }
- return crs;
- } catch (Exception e) {
- throw new ArgeoException(
- "Cannot get coordinate reference system for " + node, e);
- }
- }
-
- public static Geometry reproject(CoordinateReferenceSystem crs,
- Geometry geometry, CoordinateReferenceSystem targetCrs) {
- try {
- MathTransform transform = CRS.findMathTransform(crs, targetCrs);
- return JTS.transform(geometry, transform);
- } catch (Exception e) {
- throw new ArgeoException("Cannot reproject " + geometry + " from "
- + crs + " to " + targetCrs);
- }
- }
-}
+++ /dev/null
-package org.argeo.geotools.jcr;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import javax.jcr.Binary;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
-import org.argeo.geotools.GeoToolsConstants;
-import org.argeo.geotools.GeoToolsUtils;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.gis.GisJcrConstants;
-import org.argeo.jcr.gis.GisNames;
-import org.argeo.jcr.gis.GisTypes;
-import org.argeo.jts.jcr.JtsJcrUtils;
-import org.geotools.data.DataStore;
-import org.geotools.data.FeatureSource;
-import org.geotools.referencing.CRS;
-import org.opengis.feature.simple.SimpleFeature;
-import org.opengis.feature.simple.SimpleFeatureType;
-import org.opengis.feature.type.Name;
-import org.opengis.referencing.FactoryException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Geometry;
-import com.vividsolutions.jts.geom.Point;
-import com.vividsolutions.jts.geom.Polygon;
-
-/** Maps geographical information meta data in a JCR repository. */
-public class SimpleGeoJcrMapper implements GeoJcrMapper, GisNames {
- private final static Log log = LogFactory.getLog(SimpleGeoJcrMapper.class);
-
- private Map<String, DataStore> registeredDataStores = Collections
- .synchronizedSortedMap(new TreeMap<String, DataStore>());
-
- private Session systemSession;
-
- public void init() throws RepositoryException {
- }
-
- public void dispose() {
- if (systemSession != null)
- systemSession.logout();
- }
-
- public Map<String, List<FeatureSource<SimpleFeatureType, SimpleFeature>>> getPossibleFeatureSources() {
- Map<String, List<FeatureSource<SimpleFeatureType, SimpleFeature>>> res = new TreeMap<String, List<FeatureSource<SimpleFeatureType, SimpleFeature>>>();
- dataStores: for (String alias : registeredDataStores.keySet()) {
- DataStore dataStore = registeredDataStores.get(alias);
- List<Name> names;
- try {
- names = dataStore.getNames();
- } catch (IOException e) {
- log.warn("Cannot list features sources of data store " + alias,
- e);
- continue dataStores;
- }
- List<FeatureSource<SimpleFeatureType, SimpleFeature>> lst = new ArrayList<FeatureSource<SimpleFeatureType, SimpleFeature>>();
- for (Name name : names) {
- try {
- lst.add(dataStore.getFeatureSource(name));
- } catch (IOException e) {
- if (log.isTraceEnabled())
- log.trace("Skipping " + name + " of data store "
- + alias + " because it is probably"
- + " not a feature source", e);
- }
- }
- res.put(alias, lst);
- }
- return res;
- }
-
- // public Node getNode(String dataStoreAlias,
- // FeatureSource<SimpleFeatureType, SimpleFeature> featureSource,
- // SimpleFeature feature) {
- // StringBuffer pathBuf = new StringBuffer(dataStoresBasePath);
- // pathBuf.append('/').append(dataStoreAlias);
- // pathBuf.append('/').append(featureSource.getName());
- //
- // // TODO: use centroid or bbox to create some depth
- // // Geometry geometry = (Geometry)feature.getDefaultGeometry();
- // // Point centroid = geometry.getCentroid();
- //
- // pathBuf.append('/').append(feature.getID());
- //
- // String path = pathBuf.toString();
- // try {
- // if (session.itemExists(path))
- // return session.getNode(path);
- // else
- // return JcrUtils.mkdirs(session, path);
- // } catch (RepositoryException e) {
- // throw new ArgeoException("Cannot get feature node for " + path, e);
- // }
- // }
-
- public Node getFeatureNode(Node featureSourceNode, String featureId) {
- Binary bbox = null;
- Binary centroid = null;
- try {
- if (!featureSourceNode.hasNode(featureId)) {
- FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = getFeatureSource(featureSourceNode);
- SimpleFeature feature = GeoToolsUtils.querySingleFeature(
- featureSource, featureId);
- Node featureNode = featureSourceNode.addNode(featureId);
- featureNode.addMixin(GisTypes.GIS_FEATURE);
- Geometry geometry = (Geometry) feature.getDefaultGeometry();
-
- // SRS
- String srs;
- CoordinateReferenceSystem crs = featureSource.getSchema()
- .getCoordinateReferenceSystem();
- try {
- Integer epsgCode = CRS.lookupEpsgCode(crs, false);
- if (epsgCode != null)
- srs = "EPSG:" + epsgCode;
- else
- srs = crs.toWKT();
- } catch (FactoryException e) {
- log.warn("Cannot lookup EPSG code", e);
- srs = crs.toWKT();
- }
- featureNode.setProperty(GIS_SRS, srs);
-
- Polygon bboxPolygon;
- Geometry envelope = geometry.getEnvelope();
- if (envelope instanceof Point) {
- Point pt = (Point) envelope;
- Coordinate[] coords = new Coordinate[4];
- for (int i = 0; i < coords.length; i++)
- coords[i] = pt.getCoordinate();
- bboxPolygon = JtsJcrUtils.getGeometryFactory()
- .createPolygon(
- JtsJcrUtils.getGeometryFactory()
- .createLinearRing(coords), null);
- } else if (envelope instanceof Polygon) {
- bboxPolygon = (Polygon) envelope;
- } else {
- throw new ArgeoException("Unsupported envelope format "
- + envelope.getClass());
- }
- bbox = JtsJcrUtils.writeWkb(featureNode.getSession(),
- bboxPolygon);
- featureNode.setProperty(GIS_BBOX, bbox);
- centroid = JtsJcrUtils.writeWkb(featureNode.getSession(),
- geometry.getCentroid());
- featureNode.setProperty(GIS_CENTROID, centroid);
- featureSourceNode.getSession().save();
- return featureNode;
- } else {
- return featureSourceNode.getNode(featureId);
- }
- } catch (RepositoryException e) {
- throw new ArgeoException("Cannot get feature node for feature "
- + featureId + " from " + featureSourceNode, e);
- } finally {
- JcrUtils.closeQuietly(bbox);
- JcrUtils.closeQuietly(centroid);
- }
- }
-
- protected Node getDataStoreNode(Session session, String dataStoreAlias) {
- try {
- // normalize by starting with a '/'
- String path = dataStoreAlias.startsWith("/") ? GisJcrConstants.DATA_STORES_BASE_PATH
- + dataStoreAlias
- : GisJcrConstants.DATA_STORES_BASE_PATH + '/'
- + dataStoreAlias;
- Node dataStoreNode = JcrUtils.mkdirs(session, path,
- GisTypes.GIS_DATA_STORE);
- dataStoreNode.setProperty(GIS_ALIAS, dataStoreAlias);
- if (session.hasPendingChanges())
- session.save();
- return dataStoreNode;
- } catch (RepositoryException e) {
- JcrUtils.discardQuietly(session);
- throw new ArgeoException("Cannot get node for data store "
- + dataStoreAlias, e);
- }
- }
-
- public Node getFeatureSourceNode(Session session, String dataStoreAlias,
- FeatureSource<SimpleFeatureType, SimpleFeature> featureSource) {
- try {
- // String name = featureSource.getName().toString();
- Name name = featureSource.getName();
- String nodeName = name.getLocalPart();
- Node dataStoreNode = getDataStoreNode(session, dataStoreAlias);
- if (dataStoreNode.hasNode(nodeName))
- return dataStoreNode.getNode(nodeName);
- else {
- Node featureSourceNode = dataStoreNode.addNode(nodeName);
- featureSourceNode.addMixin(GisTypes.GIS_FEATURE_SOURCE);
- featureSourceNode.getSession().save();
- return featureSourceNode;
- }
- } catch (RepositoryException e) {
- throw new ArgeoException(
- "Cannot get feature source node for data store "
- + dataStoreAlias + " and feature source "
- + featureSource.getName(), e);
- }
- }
-
- public FeatureSource<SimpleFeatureType, SimpleFeature> getFeatureSource(
- Node node) {
- try {
- Node dataStoreNode = node.getParent();
- // TODO: check a dataStore type
- if (!dataStoreNode.hasProperty(GIS_ALIAS))
- throw new ArgeoException("Data store " + dataStoreNode
- + " is not active.");
- String alias = dataStoreNode.getProperty(GIS_ALIAS).getString();
- if (!registeredDataStores.containsKey(alias))
- throw new ArgeoException("No data store registered under "
- + dataStoreNode);
- DataStore dataStore = registeredDataStores.get(alias);
- return dataStore.getFeatureSource(node.getName());
- } catch (Exception e) {
- throw new ArgeoException("Cannot find feature source " + node, e);
- }
- }
-
- public SimpleFeature getFeature(Node node) {
- // TODO Auto-generated method stub
- return null;
- }
-
- public synchronized void register(DataStore dataStore,
- Map<String, String> properties) {
- if (!properties.containsKey(GeoToolsConstants.ALIAS_KEY)) {
- log.warn("Cannot register data store " + dataStore
- + " since it has no '" + GeoToolsConstants.ALIAS_KEY
- + "' property");
- return;
- }
- String alias = properties.get(GeoToolsConstants.ALIAS_KEY);
- Node dataStoreNode = getDataStoreNode(systemSession, alias);
- try {
- dataStoreNode.setProperty(GIS_ALIAS, alias);
-
- // TODO synchronize namespace if registered
- for (Name name : dataStore.getNames()) {
- String sourceName = name.getLocalPart();
- if (!dataStoreNode.hasNode(sourceName)) {
- Node featureSourceNode = dataStoreNode.addNode(sourceName);
- featureSourceNode.addMixin(GisTypes.GIS_FEATURE_SOURCE);
- }
- }
-
- // TODO check feature sources which are registered but not available
- // anymore
- systemSession.save();
- registeredDataStores.put(alias, dataStore);
- JcrUtils.discardQuietly(systemSession);
- } catch (Exception e) {
- throw new ArgeoException("Cannot register data store " + alias
- + ", " + dataStore, e);
- }
- }
-
- public synchronized void unregister(DataStore dataStore,
- Map<String, String> properties) {
- if (!properties.containsKey(GeoToolsConstants.ALIAS_KEY)) {
- log.warn("Cannot unregister data store " + dataStore
- + " since it has no '" + GeoToolsConstants.ALIAS_KEY
- + "' property");
- return;
- }
-
- if (!systemSession.isLive())
- return;
-
- String alias = properties.get(GeoToolsConstants.ALIAS_KEY);
- registeredDataStores.remove(alias);
- Node dataStoreNode = getDataStoreNode(systemSession, alias);
- try {
- dataStoreNode.getProperty(GIS_ALIAS).remove();
- systemSession.save();
- } catch (RepositoryException e) {
- JcrUtils.discardQuietly(systemSession);
- throw new ArgeoException("Cannot unregister data store " + alias
- + ", " + dataStore, e);
- }
- }
-
- /** Expects to own this session (will be logged out on dispose) */
- public void setSystemSession(Session systemSession) {
- this.systemSession = systemSession;
- }
-
-}
+++ /dev/null
-package org.argeo.geotools.jdbc;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.sql.DataSource;
-
-import org.argeo.ArgeoException;
-import org.geotools.data.DataStore;
-import org.geotools.data.postgis.PostgisNGDataStoreFactory;
-
-/**
- * Simplified data store to avoid issues with Spring and OSGi when Springs scans
- * for all available factory methods.
- */
-public class PostgisDataStoreFactory {
- private PostgisNGDataStoreFactory wrappedFactory = new PostgisNGDataStoreFactory();
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public DataStore createDataStore(DataSource dataSource) {
- try {
- Map params = new HashMap();
- params.put(PostgisNGDataStoreFactory.DATASOURCE.key, dataSource);
- return wrappedFactory.createDataStore(params);
- } catch (IOException e) {
- throw new ArgeoException("Cannot create PostGIS data store", e);
- }
- }
-}
+++ /dev/null
-package org.argeo.geotools.osgi;
-
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.geotools.GeoToolsConstants;
-import org.geotools.data.DataStore;
-import org.geotools.data.FileDataStoreFinder;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-/**
- * Publishes as OSGi services (typically {@link DataStore}) resources contained
- * or references within the bundle declaring this activator.
- */
-public class GisResourcesActivator implements BundleActivator {
- private final static Log log = LogFactory
- .getLog(GisResourcesActivator.class);
-
- /**
- * Keep track of the registered datastores in order to dispose them when the
- * bundle is stopped.
- */
- private Map<String, DataStore> registeredDataStores = new HashMap<String, DataStore>();
-
- @SuppressWarnings("unchecked")
- public void start(BundleContext context) throws Exception {
- Bundle bundle = context.getBundle();
-
- // TODO deal with other data types
- // shapefiles
- Enumeration<URL> resources = bundle.findEntries("/", "*.shp", true);
- while (resources.hasMoreElements()) {
- URL url = resources.nextElement();
- DataStore ds = FileDataStoreFinder.getDataStore(url);
- Properties props = new Properties();
- String alias = url.getPath();
- props.setProperty(GeoToolsConstants.ALIAS_KEY, alias);
- context.registerService(DataStore.class.getName(), ds, props);
- registeredDataStores.put(alias, ds);
- if (log.isDebugEnabled())
- log.debug("Registered data store " + alias + ": " + ds);
- }
- }
-
- public void stop(BundleContext context) throws Exception {
- for (String alias : registeredDataStores.keySet()) {
- DataStore ds = registeredDataStores.get(alias);
- try {
- ds.dispose();
- if (log.isDebugEnabled())
- log.debug("Disposed data store " + alias + ": " + ds);
- } catch (Exception e) {
- log.warn("Could not dispose data store " + ds + ": "
- + e.getMessage());
- }
- }
-
- }
-
-}
+++ /dev/null
-package org.argeo.geotools.styling;
-
-import java.awt.Color;
-
-import org.argeo.ArgeoException;
-import org.geotools.factory.CommonFactoryFinder;
-import org.geotools.filter.text.cql2.CQL;
-import org.geotools.filter.text.cql2.CQLException;
-import org.geotools.styling.FeatureTypeStyle;
-import org.geotools.styling.LineSymbolizer;
-import org.geotools.styling.Rule;
-import org.geotools.styling.Stroke;
-import org.geotools.styling.Style;
-import org.geotools.styling.StyleFactory;
-import org.opengis.filter.Filter;
-import org.opengis.filter.FilterFactory;
-
-/** Utilities related to GeoTools styling */
-public class StylingUtils {
- static StyleFactory styleFactory = CommonFactoryFinder
- .getStyleFactory(null);
- static FilterFactory filterFactory = CommonFactoryFinder
- .getFilterFactory(null);
-
- /**
- * Style for a line
- *
- * @param color
- * the AWT color in upper case
- * @param width
- * the width of the line
- * @param cqlFilter
- * filter in CQL formqt restricting the feqture upon which the
- * style will apply
- */
- public static Style createLineStyle(String color, Integer width) {
- Rule rule = styleFactory.createRule();
- rule.symbolizers().add(createLineSymbolizer(color, width));
- FeatureTypeStyle fts = styleFactory
- .createFeatureTypeStyle(new Rule[] { rule });
- Style style = styleFactory.createStyle();
- style.featureTypeStyles().add(fts);
- return style;
- }
-
- public static Style createFilteredLineStyle(String cqlFilter,
- String matchedColor, Integer matchedWidth, String unmatchedColor,
- Integer unmatchedWidth) {
- // selection filter
- Filter filter;
- try {
- filter = CQL.toFilter(cqlFilter);
- } catch (CQLException e) {
- throw new ArgeoException("Cannot parse CQL filter: " + cqlFilter, e);
- }
-
- Rule[] rules;
- // matched
- Rule ruleMatched = styleFactory.createRule();
- ruleMatched.symbolizers().add(
- createLineSymbolizer(matchedColor, matchedWidth));
- ruleMatched.setFilter(filter);
-
- // unmatched
- if (unmatchedColor != null) {
- Rule ruleUnMatched = styleFactory.createRule();
- ruleUnMatched.symbolizers().add(
- createLineSymbolizer(unmatchedColor,
- unmatchedWidth != null ? unmatchedWidth
- : matchedWidth));
- ruleUnMatched.setFilter(filterFactory.not(filter));
- rules = new Rule[] { ruleMatched, ruleUnMatched };
- } else {
- rules = new Rule[] { ruleMatched };
- }
-
- FeatureTypeStyle fts = styleFactory.createFeatureTypeStyle(rules);
- Style style = styleFactory.createStyle();
- style.featureTypeStyles().add(fts);
- return style;
- }
-
- public static LineSymbolizer createLineSymbolizer(String color,
- Integer width) {
- Stroke stroke = styleFactory.createStroke(
- filterFactory.literal(stringToColor(color)),
- filterFactory.literal(width));
- return styleFactory.createLineSymbolizer(stroke, null);
- }
-
- /**
- * Converts a string to a color, using reflection, so that other methods
- * don't need AWT dependencies in their signature. Package protected and not
- * public so that it has less impact on the overall signature.
- */
- static Color stringToColor(String color) {
- try {
- return (Color) Color.class.getField(color).get(null);
- } catch (Exception e) {
- throw new ArgeoException("Color " + color + " not found", e);
- }
- }
-}
+++ /dev/null
-package org.argeo.jts.jcr;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-
-import javax.jcr.Binary;
-import javax.jcr.Property;
-import javax.jcr.Session;
-
-import org.apache.commons.io.IOUtils;
-import org.argeo.ArgeoException;
-import org.argeo.jcr.JcrUtils;
-
-import com.vividsolutions.jts.geom.Geometry;
-import com.vividsolutions.jts.geom.GeometryFactory;
-import com.vividsolutions.jts.io.InputStreamInStream;
-import com.vividsolutions.jts.io.WKBReader;
-import com.vividsolutions.jts.io.WKBWriter;
-
-/** Utilities depending only from the JTS library. */
-public class JtsJcrUtils {
- private static GeometryFactory geometryFactory = new GeometryFactory();
- private static ThreadLocal<WKBWriter> wkbWriters = new ThreadLocal<WKBWriter>() {
- protected WKBWriter initialValue() {
- return new WKBWriter();
- }
- };
- private static ThreadLocal<WKBReader> wkbReaders = new ThreadLocal<WKBReader>() {
- protected WKBReader initialValue() {
- return new WKBReader(getGeometryFactory());
- }
- };
-
- public static GeometryFactory getGeometryFactory() {
- return geometryFactory;
- }
-
- public final static Geometry readWkb(Property property) {
- Binary wkbBinary = null;
- InputStream in = null;
- try {
- wkbBinary = property.getBinary();
- in = wkbBinary.getStream();
- WKBReader wkbReader = wkbReaders.get();
- return wkbReader.read(new InputStreamInStream(in));
- } catch (Exception e) {
- throw new ArgeoException("Cannot read WKB from " + property, e);
- } finally {
- IOUtils.closeQuietly(in);
- JcrUtils.closeQuietly(wkbBinary);
- }
- }
-
- /** The returned binary should be disposed by the caller */
- public final static Binary writeWkb(Session session, Geometry geometry) {
- Binary wkbBinary = null;
- InputStream in = null;
- try {
- WKBWriter wkbWriter = wkbWriters.get();
- byte[] arr = wkbWriter.write(geometry);
- in = new ByteArrayInputStream(arr);
- wkbBinary = session.getValueFactory().createBinary(in);
- return wkbBinary;
- } catch (Exception e) {
- throw new ArgeoException("Cannot write WKB", e);
- } finally {
- IOUtils.closeQuietly(in);
- }
- }
-}