## WEB
web:
- cd org.argeo.app.geo.js && npm run build-prod
+ cd org.argeo.app.geo.js && npm run build
npm-install:
cd org.argeo.app.geo.js && npm install
}
},
"node_modules/@babel/parser": {
- "version": "7.22.13",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.13.tgz",
- "integrity": "sha512-3l6+4YOvc9wx7VlCSw4yQfcBo01ECA8TicQfbnCPuCEpRQrf+gTUyGdxNw+pyTUyywp6JRD1w0YQs9TpBXYlkw==",
+ "version": "7.22.14",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.14.tgz",
+ "integrity": "sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
"dev": true
},
"node_modules/@types/linkify-it": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
- "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.3.tgz",
+ "integrity": "sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==",
"dev": true
},
"node_modules/@types/markdown-it": {
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001524",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001524.tgz",
- "integrity": "sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==",
+ "version": "1.0.30001525",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001525.tgz",
+ "integrity": "sha512-/3z+wB4icFt3r0USMwxujAqRvaD/B7rvGTsKhbhSQErVrJvkZCLhgNLJxU8MevahQVH6hCU9FsHdNUFbiwmE7Q==",
"dev": true,
"funding": [
{
"dev": true
},
"node_modules/electron-to-chromium": {
- "version": "1.4.505",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.505.tgz",
- "integrity": "sha512-0A50eL5BCCKdxig2SsCXhpuztnB9PfUgRMojj5tMvt8O54lbwz3t6wNgnpiTRosw5QjlJB7ixhVyeg8daLQwSQ==",
+ "version": "1.4.506",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.506.tgz",
+ "integrity": "sha512-xxGct4GPAKSRlrLBtJxJFYy74W11zX6PO9GyHgl/U+2s3Dp0ZEwAklDfNHXOWcvH7zWMpsmgbR0ggEuaYAVvHA==",
"dev": true
},
"node_modules/emoji-regex": {
}
},
"node_modules/glob": {
- "version": "10.3.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz",
- "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==",
+ "version": "10.3.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.4.tgz",
+ "integrity": "sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==",
"dev": true,
"dependencies": {
"foreground-child": "^3.1.0",
},
"dependencies": {
"@babel/parser": {
- "version": "7.22.13",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.13.tgz",
- "integrity": "sha512-3l6+4YOvc9wx7VlCSw4yQfcBo01ECA8TicQfbnCPuCEpRQrf+gTUyGdxNw+pyTUyywp6JRD1w0YQs9TpBXYlkw==",
+ "version": "7.22.14",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.14.tgz",
+ "integrity": "sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ==",
"dev": true
},
"@colors/colors": {
"dev": true
},
"@types/linkify-it": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz",
- "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.3.tgz",
+ "integrity": "sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==",
"dev": true
},
"@types/markdown-it": {
}
},
"caniuse-lite": {
- "version": "1.0.30001524",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001524.tgz",
- "integrity": "sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==",
+ "version": "1.0.30001525",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001525.tgz",
+ "integrity": "sha512-/3z+wB4icFt3r0USMwxujAqRvaD/B7rvGTsKhbhSQErVrJvkZCLhgNLJxU8MevahQVH6hCU9FsHdNUFbiwmE7Q==",
"dev": true
},
"catharsis": {
"dev": true
},
"electron-to-chromium": {
- "version": "1.4.505",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.505.tgz",
- "integrity": "sha512-0A50eL5BCCKdxig2SsCXhpuztnB9PfUgRMojj5tMvt8O54lbwz3t6wNgnpiTRosw5QjlJB7ixhVyeg8daLQwSQ==",
+ "version": "1.4.506",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.506.tgz",
+ "integrity": "sha512-xxGct4GPAKSRlrLBtJxJFYy74W11zX6PO9GyHgl/U+2s3Dp0ZEwAklDfNHXOWcvH7zWMpsmgbR0ggEuaYAVvHA==",
"dev": true
},
"emoji-regex": {
"dev": true
},
"glob": {
- "version": "10.3.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz",
- "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==",
+ "version": "10.3.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.4.tgz",
+ "integrity": "sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==",
"dev": true,
"requires": {
"foreground-child": "^3.1.0",
<arguments>
</arguments>
</buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ds.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true">
+ <implementation class="org.argeo.app.internal.geo.http.GeoJsonHttpHandler"/>
+ <service>
+ <provide interface="com.sun.net.httpserver.HttpHandler"/>
+ </service>
+ <property name="context.path" type="String" value="/api/geojson/" />
+ <property name="context.public" type="String" value="true" />
+ <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.spi.ProvidedRepository" name="ProvidedRepository" policy="static"/>
+</scr:component>
tech.units.indriya.unit,\
com.fasterxml.jackson.core,\
*
+
+Service-Component:\
+OSGI-INF/geoJsonHttpHandler.xml,\
--- /dev/null
+package org.argeo.app.geo;
+
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.api.acr.search.AndFilter;
+import org.argeo.api.acr.search.BasicSearch;
+import org.argeo.api.acr.search.ContentFilter;
+import org.geotools.filter.text.cql2.CQL;
+import org.geotools.filter.text.cql2.CQLException;
+import org.opengis.filter.And;
+import org.opengis.filter.Filter;
+import org.opengis.filter.PropertyIsEqualTo;
+import org.opengis.filter.expression.Literal;
+import org.opengis.filter.expression.PropertyName;
+
+public class CqlUtils {
+
+ public final static String CQL_FILTER = "cql_filter";
+
+ public static void filter(BasicSearch search, String cql) {
+ try {
+ filter(search, CQL.toFilter(cql));
+ } catch (CQLException e) {
+ throw new IllegalArgumentException("Cannot parse CQL: " + cql, e);
+ }
+ }
+
+ public static void filter(BasicSearch search, Filter filter) {
+ search.where((where) -> {
+ if (filter instanceof And and) {
+ processAnd(where, and);
+ } else if (filter instanceof PropertyIsEqualTo propertyIsEqualTo) {
+ processIsEqualTo(where, propertyIsEqualTo);
+ } else {
+ throw new IllegalArgumentException("Unsupported filter " + filter.getClass());
+ }
+ });
+ }
+
+ private static void processAnd(AndFilter contentFilter, And filter) {
+ for (Filter child : filter.getChildren()) {
+ if (child instanceof PropertyIsEqualTo propertyIsEqualTo) {
+ processIsEqualTo(contentFilter, propertyIsEqualTo);
+ }
+ }
+
+ }
+
+ private static void processIsEqualTo(ContentFilter<?> contentFilter, PropertyIsEqualTo propertyIsEqualTo) {
+ // TODO properly deal with types etc.
+ // see GeoTools org.geotools.filter.text.commons.ExpressionToText
+ PropertyName propertyName = (PropertyName) propertyIsEqualTo.getExpression1();
+ Literal value = (Literal) propertyIsEqualTo.getExpression2();
+ // String escaped = literal.toString().replaceAll("'", "''");
+ contentFilter.eq(NamespaceUtils.parsePrefixedName(propertyName.toString()), value.toString());
+ }
+
+ /** singleton */
+ private CqlUtils() {
+ }
+}
--- /dev/null
+package org.argeo.app.internal.geo.http;
+
+import static org.argeo.app.geo.CqlUtils.CQL_FILTER;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentSession;
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.api.acr.ldap.LdapAttr;
+import org.argeo.api.acr.spi.ProvidedRepository;
+import org.argeo.app.api.EntityType;
+import org.argeo.app.api.WGS84PosName;
+import org.argeo.app.geo.CqlUtils;
+import org.argeo.cms.http.HttpHeader;
+import org.argeo.cms.http.server.HttpServerUtils;
+import org.geotools.data.DataUtilities;
+import org.geotools.data.geojson.GeoJSONWriter;
+import org.geotools.feature.SchemaException;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.filter.text.cql2.CQL;
+import org.geotools.geometry.jts.JTSFactoryFinder;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.Point;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.filter.Filter;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+
+public class GeoJsonHttpHandler implements HttpHandler {
+ private ProvidedRepository contentRepository;
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ String path = HttpServerUtils.subPath(exchange);
+ ContentSession session = HttpServerUtils.getContentSession(contentRepository, exchange);
+ // Content content = session.get(path);
+
+ exchange.getResponseHeaders().set(HttpHeader.CONTENT_TYPE.getHeaderName(), "application/json; charset=utf-8");
+
+ Map<String, List<String>> parameters = HttpServerUtils.parseParameters(exchange);
+ String cql = parameters.containsKey(CQL_FILTER) ? parameters.get(CQL_FILTER).get(0) : null;
+
+ if (cql != null) {
+ Stream<Content> res = session.search((search) -> {
+ CqlUtils.filter(search.from(path), cql);
+ search.getWhere().isContentClass(EntityType.local);
+ });
+
+ GeoJSONWriter geoJSONWriter = new GeoJSONWriter(exchange.getResponseBody());
+ geoJSONWriter.setPrettyPrinting(true);
+
+// Writer writer = new OutputStreamWriter(exchange.getResponseBody());
+// writer.write("""
+// {
+// "type": "FeatureCollection",
+// "features": [
+// """);
+
+ SimpleFeatureType TYPE;
+ try {
+ TYPE = DataUtilities.createType("Content", "the_geom:Point:srid=4326,path:String,name:String");
+ } catch (SchemaException e) {
+ throw new RuntimeException(e);
+ }
+ SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
+ GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
+
+ res.forEach((c) -> {
+ if (!c.hasContentClass(EntityType.geopoint))
+ return;
+
+ double latitude = c.get(WGS84PosName.lat, Double.class).get();
+ double longitude = c.get(WGS84PosName.lng, Double.class).get();
+
+ Coordinate coordinate = new Coordinate(longitude, latitude);
+ Point point = geometryFactory.createPoint(coordinate);
+
+ featureBuilder.add(point);
+ String pth = c.getPath();
+ featureBuilder.add(pth);
+ featureBuilder.add(NamespaceUtils.toPrefixedName(c.getName()));
+
+ String uuid = c.attr(LdapAttr.entryUUID);
+
+ SimpleFeature feature = featureBuilder.buildFeature(uuid);
+// String json = GeoJSONWriter.toGeoJSON(feature);
+ try {
+ geoJSONWriter.write(feature);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+// writer.write("""
+// ]
+// }
+// """);
+ geoJSONWriter.close();
+ }
+
+ }
+
+ public void setContentRepository(ProvidedRepository contentRepository) {
+ this.contentRepository = contentRepository;
+ }
+
+ public static void main(String[] args) throws Exception {
+ Filter filter = CQL.toFilter("entity:type='apafField' AND jcr:isCheckedOut=false");
+ System.out.println(CQL.toCQL(filter));
+ }
+}
--- /dev/null
+package org.argeo.app.internal.geo.http;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentSession;
+import org.argeo.api.acr.spi.ProvidedRepository;
+import org.argeo.app.geo.CqlUtils;
+import org.argeo.cms.http.server.HttpServerUtils;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+
+public class GmlHttpHandler implements HttpHandler {
+ private ProvidedRepository contentRepository;
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ String path = HttpServerUtils.subPath(exchange);
+ ContentSession session = HttpServerUtils.getContentSession(contentRepository, exchange);
+// Content content = session.get(path);
+ }
+
+ public void setContentRepository(ProvidedRepository contentRepository) {
+ this.contentRepository = contentRepository;
+ }
+
+}