Mercurial > dive4elements > river
changeset 9537:bf6b63208f34
Work on uinfo inundation duration calculation.
Using proxy-wms to induce additional style information (work in progress).
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