Improve logging
[gpl/argeo-suite.git] / org.argeo.app.geo / src / org / argeo / app / geo / http / WfsHttpHandler.java
index c9a1e85c8c5867708b773a2b3d1345b6cad92090..641c14bbed9b4efc40ec6a57def5bf64257754c7 100644 (file)
@@ -29,13 +29,17 @@ import org.argeo.app.api.EntityName;
 import org.argeo.app.api.EntityType;
 import org.argeo.app.api.WGS84PosName;
 import org.argeo.app.api.geo.FeatureAdapter;
+import org.argeo.app.api.geo.WfsKvp;
 import org.argeo.app.geo.CqlUtils;
 import org.argeo.app.geo.GeoJson;
 import org.argeo.app.geo.GeoUtils;
 import org.argeo.app.geo.GpxUtils;
 import org.argeo.app.geo.JTS;
+import org.argeo.app.geo.acr.GeoEntityUtils;
 import org.argeo.cms.acr.json.AcrJsonUtils;
+import org.argeo.cms.auth.RemoteAuthUtils;
 import org.argeo.cms.http.HttpHeader;
+import org.argeo.cms.http.RemoteAuthHttpExchange;
 import org.argeo.cms.http.server.HttpServerUtils;
 import org.argeo.cms.util.LangUtils;
 import org.geotools.api.feature.GeometryAttribute;
@@ -57,7 +61,6 @@ import org.geotools.wfs.GML.Version;
 import org.locationtech.jts.geom.Coordinate;
 import org.locationtech.jts.geom.Envelope;
 import org.locationtech.jts.geom.Geometry;
-import org.locationtech.jts.geom.Point;
 import org.locationtech.jts.geom.Polygon;
 
 import com.sun.net.httpserver.HttpExchange;
@@ -71,47 +74,52 @@ public class WfsHttpHandler implements HttpHandler {
        private final static CmsLog log = CmsLog.getLog(WfsHttpHandler.class);
        private ProvidedRepository contentRepository;
 
-       // HTTP parameters
-       final static String OUTPUT_FORMAT = "outputFormat";
-       final static String TYPE_NAMES = "typeNames";
-       final static String CQL_FILTER = "cql_filter";
-       final static String BBOX = "bbox";
-
        private final Map<QName, FeatureAdapter> featureAdapters = new HashMap<>();
 
        @Override
        public void handle(HttpExchange exchange) throws IOException {
+               ContentSession session = HttpServerUtils.getContentSession(contentRepository, exchange);
+
                String path = HttpServerUtils.subPath(exchange);
 
                // content path
-               final String pathToUse;
-               int lastSlash = path.lastIndexOf('/');
+               final String pathToUse = path;
                String fileName = null;
-               if (lastSlash > 0) {
-                       fileName = path.substring(lastSlash + 1);
-               }
                boolean zipped = false;
-               if (fileName != null) {
-                       pathToUse = path.substring(0, lastSlash);
-                       if (path.endsWith(".zip")) {
-                               zipped = true;
-                       }
-               } else {
-                       pathToUse = path;
-               }
+//             int lastSlash = path.lastIndexOf('/');
+//             if (lastSlash > 0) {
+//                     fileName = path.substring(lastSlash + 1);
+//             }
+//             if (fileName != null) {
+//                     pathToUse = path.substring(0, lastSlash);
+//                     if (path.endsWith(".zip")) {
+//                             zipped = true;
+//                     }
+//             } else {
+//                     pathToUse = path;
+//             }
 
-               ContentSession session = HttpServerUtils.getContentSession(contentRepository, exchange);
-               // Content content = session.get(path);
+               Map<String, List<String>> parameters = HttpServerUtils.parseParameters(exchange);
 
                // PARAMETERS
-               Map<String, List<String>> parameters = HttpServerUtils.parseParameters(exchange);
-               String cql = getKvpParameter(parameters, CQL_FILTER);
-               String typeNamesStr = getKvpParameter(parameters, TYPE_NAMES);
-               String outputFormat = getKvpParameter(parameters, OUTPUT_FORMAT);
+               String cql = getKvpParameter(parameters, WfsKvp.CQL_FILTER);
+               String typeNamesStr = getKvpParameter(parameters, WfsKvp.TYPE_NAMES);
+               String outputFormat = getKvpParameter(parameters, WfsKvp.OUTPUT_FORMAT);
                if (outputFormat == null) {
                        outputFormat = "application/json";
                }
-               String bboxStr = getKvpParameter(parameters, BBOX);
+
+               // TODO deal with multiple
+               String formatOption = getKvpParameter(parameters, WfsKvp.FORMAT_OPTIONS);
+               if (formatOption != null) {
+                       if (formatOption.startsWith(WfsKvp.FILENAME_))
+                               fileName = formatOption.substring(WfsKvp.FILENAME_.length());
+               }
+               if (fileName != null && fileName.endsWith(".zip"))
+                       zipped = true;
+
+               // bbox
+               String bboxStr = getKvpParameter(parameters, WfsKvp.BBOX);
                if (log.isTraceEnabled())
                        log.trace(bboxStr);
                final Envelope bbox;
@@ -200,16 +208,24 @@ public class WfsHttpHandler implements HttpHandler {
                                if (featureAdapter == null)
                                        throw new IllegalStateException("No feature adapter found for " + typeName);
                                // f.isContentClass(typeName);
-                               featureAdapter.addConstraintsForFeature((AndFilter) search.getWhere(), typeName);
+                               RemoteAuthUtils.doAs(() -> {
+                                       featureAdapter.addConstraintsForFeature((AndFilter) search.getWhere(), typeName);
+                                       return null;
+                               }, new RemoteAuthHttpExchange(exchange));
                        }
 
                        if (bbox != null) {
                                search.getWhere().any((or) -> {
+                                       // box overlap, see
+                                       // https://stackoverflow.com/questions/20925818/algorithm-to-check-if-two-boxes-overlap
+                                       // isOverlapping = (x1min < x2max AND x2min < x1max AND y1min < y2max AND y2min
+                                       // < y1max)
+                                       // x1 = entity, x2 = bbox
                                        or.all((and) -> {
-                                               and.gte(EntityName.minLat, bbox.getMinX());
-                                               and.gte(EntityName.minLon, bbox.getMinY());
-                                               and.lte(EntityName.maxLat, bbox.getMaxX());
-                                               and.lte(EntityName.maxLon, bbox.getMaxY());
+                                               and.lte(EntityName.minLat, bbox.getMaxX());
+                                               and.gte(EntityName.maxLat, bbox.getMinX());
+                                               and.lte(EntityName.minLon, bbox.getMaxY());
+                                               and.gte(EntityName.maxLon, bbox.getMinY());
                                        });
                                        or.all((and) -> {
                                                and.gte(WGS84PosName.lat, bbox.getMinX());
@@ -245,14 +261,14 @@ public class WfsHttpHandler implements HttpHandler {
         * 
         * @see https://docs.ogc.org/is/09-025r2/09-025r2.html#19
         */
-       protected String getKvpParameter(Map<String, List<String>> parameters, String key) {
+       protected String getKvpParameter(Map<String, List<String>> parameters, WfsKvp key) {
                Objects.requireNonNull(key, "KVP key cannot be null");
                // let's first try the default (CAML case) which should be more efficient
-               List<String> values = parameters.get(key);
+               List<String> values = parameters.get(key.getKey());
                if (values == null) {
                        // then let's do an ignore case comparison of the key
                        keys: for (String k : parameters.keySet()) {
-                               if (key.equalsIgnoreCase(k)) {
+                               if (key.getKey().equalsIgnoreCase(k)) {
                                        values = parameters.get(k);
                                        break keys;
                                }
@@ -351,17 +367,13 @@ public class WfsHttpHandler implements HttpHandler {
                generator.writeEnd();// features array
                generator.writeEnd().close();
 
-               log.debug("GeoJSon encoding took " + (System.currentTimeMillis() - begin) + " ms.");
+               if (log.isTraceEnabled())
+                       log.trace("GeoJSon encoding took " + (System.currentTimeMillis() - begin) + " ms.");
        }
 
        protected Geometry getDefaultGeometry(Content content) {
                if (content.hasContentClass(EntityType.geopoint)) {
-                       double latitude = content.get(WGS84PosName.lat, Double.class).get();
-                       double longitude = content.get(WGS84PosName.lon, Double.class).get();
-
-                       Coordinate coordinate = new Coordinate(longitude, latitude);
-                       Point the_geom = JTS.GEOMETRY_FACTORY.createPoint(coordinate);
-                       return the_geom;
+                       return GeoEntityUtils.toPoint(content);
                }
                return null;
        }
@@ -468,7 +480,7 @@ public class WfsHttpHandler implements HttpHandler {
         */
 
        public void addFeatureAdapter(FeatureAdapter featureAdapter, Map<String, Object> properties) {
-               List<String> typeNames = LangUtils.toStringList(properties.get(TYPE_NAMES));
+               List<String> typeNames = LangUtils.toStringList(properties.get(WfsKvp.TYPE_NAMES.getKey()));
                if (typeNames.isEmpty()) {
                        log.warn("FeatureAdapter " + featureAdapter.getClass() + " does not declare type names. Ignoring it...");
                        return;
@@ -481,7 +493,7 @@ public class WfsHttpHandler implements HttpHandler {
        }
 
        public void removeFeatureAdapter(FeatureAdapter featureAdapter, Map<String, Object> properties) {
-               List<String> typeNames = LangUtils.toStringList(properties.get(TYPE_NAMES));
+               List<String> typeNames = LangUtils.toStringList(properties.get(WfsKvp.TYPE_NAMES.getKey()));
                if (!typeNames.isEmpty()) {
                        // ignore if noe type name declared
                        return;