changeset 9537:bf6b63208f34

Work on uinfo inundation duration calculation. Using proxy-wms to induce additional style information (work in progress).
author gernotbelger
date Wed, 17 Oct 2018 11:23:17 +0200
parents aa23225fd85f
children fb80fc7ec610
files artifacts/doc/conf/conf.xml artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationAccess.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationCalculation.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationCalculationResult.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationState.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/VegetationWmsResource.java
diffstat 6 files changed, 263 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/doc/conf/conf.xml	Tue Oct 16 16:42:22 2018 +0200
+++ b/artifacts/doc/conf/conf.xml	Wed Oct 17 11:23:17 2018 +0200
@@ -312,6 +312,10 @@
                 service="org.dive4elements.river.artifacts.services.SedimentLoadInfoService"
                 description="Returns sedimentloads.">org.dive4elements.artifactdatabase.DefaultServiceFactory</service-factory>
         </service-factories>
+        
+        <restful-services>
+            <restful-service class="org.dive4elements.river.artifacts.uinfo.inundationduration.VegetationWmsResource" path="/vegetationWms/{vegetation-artifact-uuid}/{wmsUrl}"/>
+        </restful-services>
 
     </factories>
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationAccess.java	Tue Oct 16 16:42:22 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationAccess.java	Wed Oct 17 11:23:17 2018 +0200
@@ -11,8 +11,10 @@
 package org.dive4elements.river.artifacts.uinfo.inundationduration;
 
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
 
-import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.access.RangeAccess;
 import org.dive4elements.river.artifacts.common.EpochYearAccessHelper;
 import org.dive4elements.river.artifacts.resources.Resources;
@@ -38,6 +40,34 @@
 
     private final EpochYearAccessHelper helper;
 
+    public static enum WmsClassification {
+        asIs {
+            @Override
+            public String configureAddress(final String serverAddress, final String url, final String vegetationZoneId) {
+                return url;
+            }
+        },
+        vegetationZone {
+            @Override
+            public String configureAddress(final String serverAddress, final String url, final String vegetationZoneId) {
+
+                try {
+                    final String urlEncoded = URLEncoder.encode(url, "UTF-8");
+                    final String vegZoneIdEncoded = URLEncoder.encode(vegetationZoneId, "UTF-8");
+
+                    return String.format("%s/%s/%s/%s", serverAddress, VegetationWmsResource.BASE_PATH, vegZoneIdEncoded, urlEncoded);
+                }
+                catch (final UnsupportedEncodingException e) {
+                    /* should never happen */
+                    e.printStackTrace();
+                    return null;
+                }
+            }
+        };
+
+        public abstract String configureAddress(String serverAddress, String url, String vegetationZoneId);
+    }
+
     // Fields from state:
     //
     // calculation_mode (String)
@@ -64,47 +94,42 @@
         return false;
     }
 
-    public WmsLayer createWMSLayer(final CallMeta meta, final String i10nKey) {
+    public WmsLayer createWMSLayer(final CallContext context, final String i10nKey, final WmsClassification classification, final String vegZoneId)
+            throws IOException, TsvReaderException {
 
         final YearType type = isUseYear() ? YearType.jahre : YearType.mittel;
         final String selectedElement = getSelectedLabel();
 
-        final String layerLabel = Resources.getMsg(meta, i10nKey, new Object[] { selectedElement });
-
-        try {
-            final UedauernConfiguration helper = UedauernConfiguration.getInstance(getRiverName(), type);
-            final String url = helper.getUrl(selectedElement);
-            final String layer = helper.getLayer(selectedElement);
+        final String layerLabel = Resources.getMsg(context.getMeta(), i10nKey, new Object[] { selectedElement });
 
-            return new WmsLayer(layerLabel, url, layer, true);
-        }
-        catch (final IOException | TsvReaderException e) {
-            e.printStackTrace();
-        }
-        return null;
-
+        return createWMSLayer(context, layerLabel, type, selectedElement, classification, vegZoneId);
     }
 
-    public WmsLayer createScenarioWMSLayer(final CallMeta meta, final String i10nKey) {
+    public WmsLayer createScenarioWMSLayer(final CallContext context, final String i10nKey, final WmsClassification classification, final String vegZoneId)
+            throws IOException, TsvReaderException {
 
         // FIXME: use scenario-cm as label, and scenario-type
         final YearType type = YearType.jahre;
-        final String selectedElement = Integer.toString(getDwspl());
-
-        final String layerLabel = Resources.getMsg(meta, i10nKey, new Object[] { selectedElement });
 
-        try {
-            final UedauernConfiguration helper = UedauernConfiguration.getInstance(getRiverName(), type);
-            final String url = helper.getUrl(selectedElement);
-            final String layer = helper.getLayer(selectedElement);
+        final String selectedElement = Integer.toString(getDwspl());
+        final String layerLabel = Resources.getMsg(context.getMeta(), i10nKey, new Object[] { selectedElement });
 
-            return new WmsLayer(layerLabel, url, layer, false);
-        }
-        catch (final IOException | TsvReaderException e) {
-            e.printStackTrace();
-        }
-        return null;
+        return createWMSLayer(context, layerLabel, type, selectedElement, classification, vegZoneId);
+    }
 
+    private WmsLayer createWMSLayer(final CallContext context, final String layerLabel, final YearType type, final String selectedElement,
+            final WmsClassification classification, final String vegZoneId)
+                    throws IOException, TsvReaderException {
+
+        final String serverAddress = context.getDatabase().getServerAddress();
+
+        final UedauernConfiguration config = UedauernConfiguration.getInstance(getRiverName(), type);
+        final String url = config.getUrl(selectedElement);
+        final String layer = config.getLayer(selectedElement);
+
+        final String realUrl = classification.configureAddress(serverAddress, url, vegZoneId);
+
+        return new WmsLayer(layerLabel, realUrl, layer, classification == WmsClassification.asIs);
     }
 
     private String getSelectedLabel() {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationCalculation.java	Tue Oct 16 16:42:22 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationCalculation.java	Wed Oct 17 11:23:17 2018 +0200
@@ -9,12 +9,15 @@
  */
 package org.dive4elements.river.artifacts.uinfo.inundationduration;
 
+import java.io.IOException;
 import java.util.List;
 
 import org.dive4elements.artifacts.CallContext;
 import org.dive4elements.river.artifacts.model.Calculation;
 import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.sinfo.tkhstate.TsvHelper.TsvReaderException;
 import org.dive4elements.river.artifacts.uinfo.UINFOArtifact;
+import org.dive4elements.river.artifacts.uinfo.inundationduration.InundationDurationAccess.WmsClassification;
 import org.dive4elements.river.artifacts.uinfo.inundationduration.InundationDurationCalculationResult.WmsLayer;
 import org.dive4elements.river.artifacts.uinfo.vegetationzones.VegetationZoneServerClientXChange;
 
@@ -33,35 +36,46 @@
     public CalculationResult calculate(final UINFOArtifact uinfo) {
         final Calculation problems = new Calculation();
 
-        final InundationDurationAccess indurax = new InundationDurationAccess(uinfo);
-
-        final String zonesRaw = indurax.getVegZones();
-        final List<VegetationZoneServerClientXChange> zones = VegetationZoneServerClientXChange.parse(zonesRaw);
-
-        final boolean isUseScenario = indurax.getIsUseScenario();
-
-        final InundationDurationCalculationResult result = new InundationDurationCalculationResult();
-
-        final WmsLayer inundationDurationLayer = indurax.createWMSLayer(this.context.getMeta(), "uinfo.export.url.inundationduration.inundationduration");
-        result.addLayer(inundationDurationLayer);
+        try {
+            final InundationDurationAccess indurax = new InundationDurationAccess(uinfo);
 
-        // TODO: add vegetationzone-values as parameter to url and use this url as veg'zone'url
-        final WmsLayer vegetationLayer = indurax.createWMSLayer(this.context.getMeta(), "uinfo.export.url.inundationduration.vegetation");
-        result.addLayer(vegetationLayer);
+            final String zonesRaw = indurax.getVegZones();
+            final List<VegetationZoneServerClientXChange> zones = VegetationZoneServerClientXChange.parse(zonesRaw);
+            // FIXME: instead find out a-uuid of referenced vegetations
+            // FIXME:
+            final String vegZoneId = "unknown";
 
-        if (isUseScenario) {
-            // TODO: wieder einkommentieren, sobald die URL-Definition für Szenarien geklärt ist (und hoffentlich analog zu "mittel"
-            // und "jahre" funktioniert)
-            // final WmsLayer scenarioInundationDurationLayer = indurax.createScenarioWMSLayer(this.context.getMeta(),
-            // "uinfo.export.url.inundationduration.scenario");
-            // result.addLayer(scenarioInundationDurationLayer);
-            //
-            // // TODO: add vegetationzone-values as styles to layer
-            // final WmsLayer scenarioVegetationLayer = indurax.createScenarioWMSLayer(this.context.getMeta(),
-            // "uinfo.export.url.inundationduration.vegetation_scenario");
-            // result.addLayer(scenarioVegetationLayer);
+            final boolean isUseScenario = indurax.getIsUseScenario();
+
+            final InundationDurationCalculationResult result = new InundationDurationCalculationResult();
+
+            final WmsLayer inundationDurationLayer = indurax.createWMSLayer(this.context, "uinfo.export.url.inundationduration.inundationduration",
+                    WmsClassification.asIs, vegZoneId);
+            result.addLayer(inundationDurationLayer);
+
+            final WmsLayer vegetationLayer = indurax.createWMSLayer(this.context, "uinfo.export.url.inundationduration.vegetation",
+                    WmsClassification.vegetationZone, vegZoneId);
+            result.addLayer(vegetationLayer);
+
+            if (isUseScenario) {
+                // TODO: wieder einkommentieren, sobald die URL-Definition für Szenarien geklärt ist (und hoffentlich analog zu "mittel"
+                // und "jahre" funktioniert)
+                // final WmsLayer scenarioInundationDurationLayer = indurax.createScenarioWMSLayer(this.context.getMeta(),
+                // "uinfo.export.url.inundationduration.scenario");
+                // result.addLayer(scenarioInundationDurationLayer);
+                //
+                // // TODO: add vegetationzone-values as styles to layer
+                // final WmsLayer scenarioVegetationLayer = indurax.createScenarioWMSLayer(this.context.getMeta(),
+                // "uinfo.export.url.inundationduration.vegetation_scenario");
+                // result.addLayer(scenarioVegetationLayer);
+            }
+
+            return new CalculationResult(result, problems);
         }
-
-        return new CalculationResult(result, problems);
+        catch (IOException | TsvReaderException e) {
+            e.printStackTrace();
+            problems.addProblem("Invalid server configuration: " + e.getLocalizedMessage());
+            return new CalculationResult(null, problems);
+        }
     }
 }
\ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationCalculationResult.java	Tue Oct 16 16:42:22 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationCalculationResult.java	Wed Oct 17 11:23:17 2018 +0200
@@ -18,10 +18,16 @@
  */
 final class InundationDurationCalculationResult implements Serializable {
 
-    public static final class WmsLayer {
+    public static final class WmsLayer implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
         private final String label;
+
         private final String url;
+
         private final boolean showLayerLink;
+
         private final String layer;
 
         public WmsLayer(final String label, final String url, final String layer, final boolean showLayerLink) {
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationState.java	Tue Oct 16 16:42:22 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/InundationDurationState.java	Wed Oct 17 11:23:17 2018 +0200
@@ -108,8 +108,6 @@
             index++; // because super.computeAdvance adds the river theme with index 0
         }
 
-        // tODO: create layer links: filter by "showLayerLink"
-
         final Calculation report = res.getReport();
         if (report.hasProblems())
             facets.add(new ReportFacet(ComputeType.ADVANCE, hash, this.id));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/VegetationWmsResource.java	Wed Oct 17 11:23:17 2018 +0200
@@ -0,0 +1,157 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.artifacts.uinfo.inundationduration;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.imageio.ImageIO;
+
+import org.dive4elements.artifactdatabase.rest.BaseResource;
+import org.restlet.Client;
+import org.restlet.Context;
+import org.restlet.Request;
+import org.restlet.Response;
+import org.restlet.data.Form;
+import org.restlet.data.MediaType;
+import org.restlet.data.Method;
+import org.restlet.data.Protocol;
+import org.restlet.data.Reference;
+import org.restlet.data.Status;
+import org.restlet.representation.OutputRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.ResourceException;
+
+/**
+ * Proof of context wms proxy.
+ *
+ * @author Gernot Belger
+ */
+public class VegetationWmsResource extends BaseResource {
+
+    public static final String BASE_PATH = "vegetationWms";
+
+    private static final String ATTRIBUTE_VEGETATION_ARTIFACT_UUID = "vegetation-artifact-uuid";
+
+    private static final String ATTRIBUTE_WMS_URL = "wmsUrl";
+
+    private static final ThreadLocal<Client> CLIENT = new ThreadLocal<Client>() {
+        @Override
+        protected Client initialValue() {
+
+            final List<Protocol> protocols = Arrays.asList(Protocol.HTTPS, Protocol.HTTP);
+            final Client client = new Client(new Context(), protocols);
+            // FIXME
+            client.getContext().getParameters().add("proxyHost", "proxy.bce01.de");
+            client.getContext().getParameters().add("proxyPort", "8080");
+            return client;
+        }
+    };
+
+    @Override
+    protected Representation innerGet() throws ResourceException {
+
+        try {
+            final Request request = getRequest();
+
+            final Map<String, Object> attributes = request.getAttributes();
+            final String vegArtifactUuid = (String) attributes.get(ATTRIBUTE_VEGETATION_ARTIFACT_UUID);
+            final String baseUrl = (String) attributes.get(ATTRIBUTE_WMS_URL);
+
+            final Reference originalRef = request.getOriginalRef();
+            final String query = originalRef.getQuery();
+
+            final Form queryAsForm = originalRef.getQueryAsForm();
+            final boolean isGetMap = "GetMap".equalsIgnoreCase(queryAsForm.getFirstValue("REQUEST", true));
+
+            final String decodedBaseUrl = URLDecoder.decode(baseUrl, "UTF-8");
+
+            final Reference proxyReference = new Reference(decodedBaseUrl);
+            proxyReference.setQuery(query);
+
+            final Client client = CLIENT.get();
+
+            final Request proxyRequest = new Request(Method.GET, proxyReference);
+            final Response response = client.handle(proxyRequest);
+
+            final Status status = response.getStatus();
+
+            if (!Status.SUCCESS_OK.equals(status))
+                throw new ResourceException(status);
+
+            final Representation entity = response.getEntity();
+
+            /* simply redirect everything that is not an png image */
+            if (!isGetMap)
+                return entity;
+
+            final MediaType mediaType = entity.getMediaType();
+            if (!MediaType.IMAGE_ALL.getMainType().equals(mediaType.getMainType()))
+                return entity;
+
+            try {
+                final BufferedImage image = ImageIO.read(entity.getStream());
+
+                // FIXME: tweak image...
+                final WritableRaster raster = image.getRaster();
+                final int width = raster.getWidth();
+                final int height = raster.getHeight();
+                final int numBands = raster.getNumBands();
+                for (int x = 0; x < width; x++) {
+                    for (int y = 0; y < height; y++) {
+
+                        // final double sampleDouble = raster.getSampleDouble(x, y, 0);
+
+                        final int red = raster.getSample(x, y, 0);
+                        final int green = raster.getSample(x, y, 1);
+                        final int blue = raster.getSample(x, y, 2);
+                        final int alpha = raster.getSample(x, y, 3);
+
+                        raster.setSample(x, y, 0, green);
+                        raster.setSample(x, y, 1, red);
+                        raster.setSample(x, y, 2, blue);
+                        raster.setSample(x, y, 3, alpha);
+                    }
+                }
+
+
+                final Representation newResponse = new OutputRepresentation(mediaType) {
+
+                    @Override
+                    public void write(final OutputStream outputStream) throws IOException {
+
+                        // REMARK: in most cases the media-subtype can be used as image-format name.
+                        final String subType = mediaType.getSubType();
+                        ImageIO.write(image, subType, outputStream);
+
+                    }
+                };
+
+                return newResponse;
+            }
+            catch (final IOException e) {
+                e.printStackTrace();
+                throw new ResourceException(Status.SERVER_ERROR_INTERNAL, e);
+            }
+
+        }
+        catch (final UnsupportedEncodingException e) {
+            e.printStackTrace();
+            throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, e);
+        }
+    }
+}
\ No newline at end of file

http://dive4elements.wald.intevation.org