# HG changeset patch # User gernotbelger # Date 1532421543 -7200 # Node ID 82c67b859aa771de5df19776d2eb2bf1aa9415aa # Parent 6c88ad449c832b809ae027b040d7f82caf0d43c7 bundu.bezugswst worklflow incl. service impl for mainValues to be calculated diff -r 6c88ad449c83 -r 82c67b859aa7 artifacts/doc/conf/artifacts/bundu.xml --- a/artifacts/doc/conf/artifacts/bundu.xml Tue Jul 24 10:36:18 2018 +0200 +++ b/artifacts/doc/conf/artifacts/bundu.xml Tue Jul 24 10:39:03 2018 +0200 @@ -327,7 +327,7 @@ - + @@ -390,8 +390,9 @@ - + + diff -r 6c88ad449c83 -r 82c67b859aa7 artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BunduWstWQFixing.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BunduWstWQFixing.java Tue Jul 24 10:36:18 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/BunduWstWQFixing.java Tue Jul 24 10:39:03 2018 +0200 @@ -12,7 +12,6 @@ import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.common.utils.XMLUtils; import org.dive4elements.river.artifacts.D4EArtifact; -import org.dive4elements.river.artifacts.model.RangeWithValues; import org.dive4elements.river.artifacts.states.WQAdapted; import org.w3c.dom.Element; @@ -23,6 +22,8 @@ */ public class BunduWstWQFixing extends WQAdapted { + private static final long serialVersionUID = 1L; + /** The log used in this state. */ private static Logger log = Logger.getLogger(BunduWstWQFixing.class); @@ -31,45 +32,30 @@ return "bundu_wst_wq_panel"; } - /** Simple sanity check if values are positive numbers **/ @Override public boolean validate(final Artifact artifact) throws IllegalArgumentException { - log.debug("BunduWstWQFixing.validate"); - - final RangeWithValues[] rwvs = extractInput(getData((D4EArtifact) artifact, "wq_values")); - - if (rwvs == null) { - throw new IllegalArgumentException("error_missing_wq_data"); - } - for (final RangeWithValues rwv : rwvs) { - final double[] values = rwv.getValues(); - for (final double val : values) { - if (val <= 0) { - throw new IllegalArgumentException("error_validate_positive"); - } - } - } - + // Validation is done on client side. No wrong inputs should arrive here. + // Validation in Super is not suitable for this case return true; } // adding bezugsjahr and dauer to client - @Override protected Element[] createItems(final XMLUtils.ElementCreator ec, final Artifact artifact, final String name, final CallContext context) { final Element[] defaultElements = super.createItems(ec, artifact, name, context); - - final BunduAccess access = new BunduAccess((D4EArtifact) artifact); + if (name.equals("bundu.wst.mode")) { // random-name eines DataItems vom state (s. bundu.xml), sodass verhindert wird, dass an alle DataItems + // length+bezugsjahr drangehängt werden + final BunduAccess access = new BunduAccess((D4EArtifact) artifact); - final int bezugsjahr = access.getBezugsJahr(); - final int qSeriesLength = access.getQSeriesLength(); - final String[] keys = new String[] { "ignore_q_series_length", "ignore_bezugsjahr" }; - final String[] values = new String[] { String.valueOf(qSeriesLength), String.valueOf(bezugsjahr) }; + final int bezugsjahr = access.getBezugsJahr(); + final int qSeriesLength = access.getQSeriesLength(); + final String[] keys = new String[] { "ignore_q_series_length", "ignore_bezugsjahr" }; + final String[] values = new String[] { String.valueOf(qSeriesLength), String.valueOf(bezugsjahr) }; - return FixationChoice.appendElements(ec, defaultElements, keys, values); - + return FixationChoice.appendElements(ec, defaultElements, keys, values); + } else + return defaultElements; } - -} +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/FixationChoice.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/FixationChoice.java Tue Jul 24 10:36:18 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/bundu/bezugswst/FixationChoice.java Tue Jul 24 10:39:03 2018 +0200 @@ -65,14 +65,15 @@ public static final Element[] appendElements(final ElementCreator ec, final Element[] defaultElements, final String[] keys, final String[] values) { assert (values.length == keys.length); // make bigger array - final Element[] defaultAndAddedElements = new Element[defaultElements.length + values.length]; + final int defaultLength = defaultElements == null ? 0 : defaultElements.length; + final Element[] defaultAndAddedElements = new Element[defaultLength + values.length]; - for (int i = 0; i < defaultElements.length; i++) { + for (int i = 0; i < defaultLength; i++) { defaultAndAddedElements[i] = defaultElements[i]; } // add the new values: for (int j = 0; j < keys.length; j++) { - defaultAndAddedElements[defaultElements.length + j] = createItem(ec, new String[] { keys[j], values[j] }); + defaultAndAddedElements[defaultLength + j] = createItem(ec, new String[] { keys[j], values[j] }); } return defaultAndAddedElements; } diff -r 6c88ad449c83 -r 82c67b859aa7 artifacts/src/main/java/org/dive4elements/river/artifacts/services/AbstractMainValuesService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/AbstractMainValuesService.java Tue Jul 24 10:39:03 2018 +0200 @@ -0,0 +1,255 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * 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.services; + +import static org.dive4elements.river.backend.utils.EpsilonComparator.CMP; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.dive4elements.artifacts.common.ArtifactNamespaceContext; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; +import org.dive4elements.river.artifacts.model.RiverFactory; +import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.model.MainValue; +import org.dive4elements.river.model.MainValueType; +import org.dive4elements.river.model.NamedMainValue; +import org.dive4elements.river.model.OfficialLine; +import org.dive4elements.river.model.Range; +import org.dive4elements.river.model.River; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * @author Ingo Weinzierl + */ +abstract class AbstractMainValuesService extends D4EService { + + private static final long serialVersionUID = 1L; + + public static final class MainValuesServiceException extends Exception { + + private static final long serialVersionUID = 1L; + + public MainValuesServiceException(final String message) { + super(message); + } + } + + /** The log that is used by this service. */ + private static Logger log = Logger.getLogger(AbstractMainValuesService.class); + + /** XPath that points to the river definition of the incoming request. */ + private static final String XPATH_RIVER = "/art:mainvalues/art:river/text()"; + + /** XPath that points to the start definition of the incoming request. */ + private static final String XPATH_START = "/art:mainvalues/art:start/text()"; + + /** The XPath that points to the end definition of the incoming request. */ + private static final String XPATH_END = "/art:mainvalues/art:end/text()"; + + protected static final Document error(final String msg) { + log.debug(msg); + return XMLUtils.newDocument(); + } + + /** + * This method extracts the river from the incoming request. If no river + * string was found or no river is found in the database based on this + * string a NullPointerException is thrown. + * + * @param data + * The incoming request data. + * + * @return the River object. + */ + protected final River getRequestedRiver(final Document data) throws MainValuesServiceException { + log.debug("MainValuesService.getRequestedRiver"); + + String riverStr = XMLUtils.xpathString(data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE); + + if (riverStr != null && (riverStr = riverStr.trim()).length() > 0) + return RiverFactory.getRiver(riverStr); + + throw new MainValuesServiceException("no river found."); + } + + protected final Gauge getRequestedGauge(final Document data, final River river) throws MainValuesServiceException { + + final double[] minmax = getRequestedStartEnd(data, river); + final Gauge gauge = river.determineRefGauge(minmax, CMP.compare(minmax[0], minmax[1]) != 0); + if (gauge == null) + throw new MainValuesServiceException("no gauge found."); + + return gauge; + } + + /** + * This method extracts the start and end point from incoming request + * document and returns both values in an array. + * If no start and end strings + * are found in the document, the min/max values of the river are + * returned. + * + * @param data + * The incoming request data. + * @param river + * The river of the request. + * + * @return the start and end point. + */ + private double[] getRequestedStartEnd(final Document data, final River river) { + log.debug("MainValuesService.getStartEnd"); + + final String startStr = XMLUtils.xpathString(data, XPATH_START, ArtifactNamespaceContext.INSTANCE); + + final String endStr = XMLUtils.xpathString(data, XPATH_END, ArtifactNamespaceContext.INSTANCE); + + if (startStr == null || endStr == null) { + return river.determineMinMaxDistance(); + } + + try { + final double start = Double.parseDouble(startStr); + final double end = Double.parseDouble(endStr); + + if (log.isDebugEnabled()) { + log.debug("Found start: " + start); + log.debug("Found end: " + end); + } + + return new double[] { start, end }; + } + catch (final NumberFormatException nfe) { + log.warn(nfe, nfe); + return river.determineMinMaxDistance(); + } + } + + protected final Document buildDocument(final River river, final Gauge gauge, final List mainValues, final Object context) { + log.debug("MainValuesService.buildDocument"); + + final Document doc = XMLUtils.newDocument(); + + final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); + + final Element rootEl = cr.create("service"); + cr.addAttr(rootEl, "name", "mainvalues"); + + doc.appendChild(rootEl); + + appendMetaInformation(doc, rootEl, river, gauge, context); + appendMainValues(doc, rootEl, mainValues, river.getId(), context); + + return doc; + } + + /** + * This method appends some meta information to the result document. + * Currently, the river's and gauge's names and the gauge's range are + * appended. + * + * @param root + * The root element of the result document. + * @param river + * The river. + * @param gauge + * The gauge. + * @param context + * The context object. + */ + private void appendMetaInformation(final Document doc, final Element root, final River river, final Gauge gauge, final Object context) { + log.debug("MainValuesService.appendMetaInformation"); + + final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); + + final Range range = gauge.getRange(); + + final Element riverEl = cr.create("river"); + cr.addAttr(riverEl, "name", river.getName()); + + final Element gaugeEl = cr.create("gauge"); + cr.addAttr(gaugeEl, "name", gauge.getName()); + cr.addAttr(gaugeEl, "from", range.getA().toString()); + cr.addAttr(gaugeEl, "to", range.getB().toString()); + + root.appendChild(riverEl); + root.appendChild(gaugeEl); + } + + /** Checks i a main value has an official associated, */ + private static boolean hasOfficialLine(final NamedMainValue nmv, final Integer riverId) { + for (final OfficialLine ol : nmv.getOfficialLines()) { + if (ol.getWstColumn().getWst().getRiver().getId().equals(riverId)) { + return true; + } + } + return false; + } + + /** Append xml representation of main values to document. */ + private void appendMainValues(final Document doc, final Element root, final List mainValues, final Integer riverId, final Object context) { + log.debug("MainValuesService.appendMainValues"); + + final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); + + final Element list = cr.create("mainvalues"); + + for (final MainValue mainValue : mainValues) { + final Element newEl = buildMainValueElement(doc, mainValue, riverId, context); + + if (newEl != null) { + list.appendChild(newEl); + } + } + + root.appendChild(list); + } + + /** + * This method builds a concrete mainvalue element. This element consists of + * three attributes: the value, its name and its type. + * + * @param doc + * The owner document. + * @param mainValue + * The mainvalue. + * @param context + * The context object. + * + * @return a mainvalue element. + */ + private Element buildMainValueElement(final Document doc, final MainValue mainValue, final Integer riverId, final Object context) { + final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX); + + final NamedMainValue namedMainValue = mainValue.getMainValue(); + final MainValueType mainValueType = namedMainValue.getType(); + + final Element el = cr.create("mainvalue"); + + cr.addAttr(el, "value", mainValue.getValue().toString()); + cr.addAttr(el, "name", namedMainValue.getName()); + cr.addAttr(el, "type", mainValueType.getName()); + if (mainValue.getTimeInterval() != null) { + if (mainValue.getTimeInterval().getStartTime() != null) { + cr.addAttr(el, "starttime", Long.toString(mainValue.getTimeInterval().getStartTime().getTime())); + } + if (mainValue.getTimeInterval().getStopTime() != null) { + cr.addAttr(el, "stoptime", Long.toString(mainValue.getTimeInterval().getStopTime().getTime())); + } + } + + if (hasOfficialLine(namedMainValue, riverId)) { + cr.addAttr(el, "official", "true"); + } + + return el; + } +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesService.java Tue Jul 24 10:39:03 2018 +0200 @@ -0,0 +1,146 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * 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.services; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import org.dive4elements.artifacts.CallMeta; +import org.dive4elements.artifacts.GlobalContext; +import org.dive4elements.artifacts.common.ArtifactNamespaceContext; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.model.MainValue; +import org.dive4elements.river.model.MainValueType; +import org.dive4elements.river.model.MainValueType.MainValueTypeKey; +import org.dive4elements.river.model.NamedMainValue; +import org.dive4elements.river.model.OfficialLine; +import org.dive4elements.river.model.River; +import org.dive4elements.river.model.TimeInterval; +import org.w3c.dom.Document; + +/** + * This service returns the main values of a river's gauge based on the start + * and end point of the river. + * + * @author Ingo Weinzierl + */ +public class DynamicMainValuesService extends AbstractMainValuesService { + + private static final long serialVersionUID = 1L; + + private static final String XPATH_START_YEAR = "/art:mainvalues/art:startYear/text()"; + + private static final String XPATH_END_YEAR = "/art:mainvalues/art:endYear/text()"; + + @Override + public Document doProcess(final Document data, final GlobalContext context, final CallMeta callMeta) { + try { + + final River river = getRequestedRiver(data); + final Gauge gauge = getRequestedGauge(data, river); + final Date startTime = getRequestedStartYear(data); + final Date endTime = getRequestedEndYear(data); + + final List mainValues = getMainValues(river, gauge, startTime, endTime); + + return buildDocument(river, gauge, mainValues, context); + } + catch (final MainValuesServiceException e) { + e.printStackTrace(); + return error(e.getMessage()); + } + } + + private Date getRequestedStartYear(final Document data) throws MainValuesServiceException { + + final String startStr = XMLUtils.xpathString(data, XPATH_START_YEAR, ArtifactNamespaceContext.INSTANCE); + + if (startStr == null) + throw new MainValuesServiceException("no start year"); + + try { + final int year = Integer.parseInt(startStr); + + // FIXME: timezone? probably must match timezone of database + final Calendar cal = Calendar.getInstance(); + cal.clear(); + cal.set(year, 0, 1); + return cal.getTime(); + } + catch (final NumberFormatException e) { + e.printStackTrace(); + throw new MainValuesServiceException("invalid start year"); + } + } + + private Date getRequestedEndYear(final Document data) throws MainValuesServiceException { + + final String endStr = XMLUtils.xpathString(data, XPATH_END_YEAR, ArtifactNamespaceContext.INSTANCE); + + if (endStr == null) + throw new MainValuesServiceException("no end year"); + + try { + final int year = Integer.parseInt(endStr); + + // FIXME: timezone? probably must match timezone of database + final Calendar cal = Calendar.getInstance(); + cal.clear(); + cal.set(year, 11, 31); + return cal.getTime(); + } + catch (final NumberFormatException e) { + e.printStackTrace(); + throw new MainValuesServiceException("invalid end year"); + } + } + + /** + * This method creates the result document that includes the main values of + * the specified gauge. + * + * @param river + * The river. + * @param gauge + * The gauge. + * @param endYear + * @param startYear + * + * @return a document that includes the main values of the specified river + * at the specified gauge. + */ + protected List getMainValues(final River river, final Gauge gauge, final Date startTime, final Date endTime) { + + // TODO: compute our own main values from the discharge timeseries. + + // final List mainValues = gauge.getMainValues(); + final List mainValues = new ArrayList<>(); + + final MainValue myMain = new MainValue(); + + // TODO: fetch real NamedMainValue from database: GLQ20, MNQ, MQ, MHQ, HQ5 + Dauerzahlen + final NamedMainValue mainValue = new NamedMainValue("Testname", new MainValueType(MainValueTypeKey.Q.getName())); + mainValue.setOfficialLines(new ArrayList()); + + myMain.setMainValue(mainValue); + // FIXME: compute value + myMain.setValue(new BigDecimal("1234.567")); + + final TimeInterval timeInterval = new TimeInterval(startTime, endTime); + myMain.setTimeInterval(timeInterval); + + mainValues.add(myMain); + + return mainValues; + } +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 artifacts/src/main/java/org/dive4elements/river/artifacts/services/MainValuesService.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/MainValuesService.java Tue Jul 24 10:36:18 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/MainValuesService.java Tue Jul 24 10:39:03 2018 +0200 @@ -11,29 +11,12 @@ import java.util.List; import org.apache.log4j.Logger; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - import org.dive4elements.artifacts.CallMeta; import org.dive4elements.artifacts.GlobalContext; - -import org.dive4elements.artifacts.common.ArtifactNamespaceContext; -import org.dive4elements.artifacts.common.utils.XMLUtils; -import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; - import org.dive4elements.river.model.Gauge; import org.dive4elements.river.model.MainValue; -import org.dive4elements.river.model.MainValueType; -import org.dive4elements.river.model.NamedMainValue; -import org.dive4elements.river.model.OfficialLine; -import org.dive4elements.river.model.Range; import org.dive4elements.river.model.River; - -import org.dive4elements.river.artifacts.model.RiverFactory; - -import static org.dive4elements.river.backend.utils.EpsilonComparator.CMP; - +import org.w3c.dom.Document; /** * This service returns the main values of a river's gauge based on the start @@ -41,143 +24,42 @@ * * @author Ingo Weinzierl */ -public class MainValuesService extends D4EService { - - /** The log that is used by this service.*/ - private static Logger log = Logger.getLogger(MainValuesService.class); - - /** XPath that points to the river definition of the incoming request.*/ - public static final String XPATH_RIVER = - "/art:mainvalues/art:river/text()"; - - /** XPath that points to the start definition of the incoming request.*/ - public static final String XPATH_START = - "/art:mainvalues/art:start/text()"; +public class MainValuesService extends AbstractMainValuesService { - /** The XPath that points to the end definition of the incoming request.*/ - public static final String XPATH_END = "/art:mainvalues/art:end/text()"; - - protected CallMeta callMeta; - + private static final long serialVersionUID = 1L; - /** - * The default constructor. - */ - public MainValuesService() { - } - - private static final Document error(String msg) { - log.debug(msg); - return XMLUtils.newDocument(); - } - + /** The log that is used by this service. */ + private static Logger log = Logger.getLogger(MainValuesService.class); @Override - public Document doProcess( - Document data, - GlobalContext context, - CallMeta callMeta - ) { - log.debug("MainValuesService.process"); - - this.callMeta = callMeta; - - River river = getRequestedRiver(data); - if (river == null) { - return error("no river found."); - } - - double[] minmax = getRequestedStartEnd(data, river); - Gauge gauge = river.determineRefGauge(minmax, - CMP.compare(minmax[0], minmax[1]) != 0); - - if (gauge == null) { - return error("no gauge found."); - } - - List mainValues = getMainValues(river, gauge); - - return buildDocument(river, gauge, mainValues, context); - } - - - /** - * This method extracts the river from the incoming request. If no river - * string was found or no river is found in the database based on this - * string a NullPointerException is thrown. - * - * @param data The incoming request data. - * - * @return the River object. - */ - protected River getRequestedRiver(Document data) - throws NullPointerException - { - log.debug("MainValuesService.getRequestedRiver"); - - String riverStr = XMLUtils.xpathString( - data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE); + public Document doProcess(final Document data, final GlobalContext context, final CallMeta callMeta) { + try { + final River river = getRequestedRiver(data); + final Gauge gauge = getRequestedGauge(data, river); - return riverStr != null && (riverStr = riverStr.trim()).length() > 0 - ? RiverFactory.getRiver(riverStr) - : null; - } - - - /** - * This method extracts the start and end point from incoming request - * document and returns both values in an array. - * If no start and end strings - * are found in the document, the min/max values of the river are - * returned. - * - * @param data The incoming request data. - * @param river The river of the request. - * - * @return the start and end point. - */ - protected double[] getRequestedStartEnd(Document data, River river) { - log.debug("MainValuesService.getStartEnd"); + final List mainValues = getMainValues(river, gauge); - String startStr = XMLUtils.xpathString( - data, XPATH_START, ArtifactNamespaceContext.INSTANCE); - - String endStr = XMLUtils.xpathString( - data, XPATH_END, ArtifactNamespaceContext.INSTANCE); - - if (startStr == null || endStr == null) { - return river.determineMinMaxDistance(); + return buildDocument(river, gauge, mainValues, context); } - - try { - double start = Double.parseDouble(startStr); - double end = Double.parseDouble(endStr); - - if (log.isDebugEnabled()) { - log.debug("Found start: " + start); - log.debug("Found end: " + end); - } - - return new double[] { start, end }; - } - catch (NumberFormatException nfe) { - log.warn(nfe, nfe); - return river.determineMinMaxDistance(); + catch (final MainValuesServiceException e) { + e.printStackTrace(); + return error(e.getMessage()); } } - /** * This method creates the result document that includes the main values of * the specified gauge. * - * @param river The river. - * @param gauge The gauge. + * @param river + * The river. + * @param gauge + * The gauge. * * @return a document that includes the main values of the specified river - * at the specified gauge. + * at the specified gauge. */ - protected List getMainValues(River river, Gauge gauge) { + protected List getMainValues(final River river, final Gauge gauge) { if (log.isDebugEnabled()) { log.debug("MainValuesService.buildMainValues"); @@ -185,7 +67,7 @@ log.debug("Gauge: " + gauge.getName()); } - List mainValues = gauge.getMainValues(); + final List mainValues = gauge.getMainValues(); if (log.isDebugEnabled()) { log.debug(mainValues.size() + " main values found."); @@ -193,167 +75,4 @@ return mainValues; } - - - protected Document buildDocument( - River river, - Gauge gauge, - List mainValues, - Object context) - { - log.debug("MainValuesService.buildDocument"); - - Document doc = XMLUtils.newDocument(); - - ElementCreator cr = new ElementCreator( - doc, - ArtifactNamespaceContext.NAMESPACE_URI, - ArtifactNamespaceContext.NAMESPACE_PREFIX); - - Element rootEl = cr.create("service"); - cr.addAttr(rootEl, "name", "mainvalues"); - - doc.appendChild(rootEl); - - appendMetaInformation(doc, rootEl, river, gauge, context); - appendMainValues(doc, rootEl, mainValues, river.getId(), context); - - return doc; - } - - - /** - * This method appends some meta information to the result document. - * Currently, the river's and gauge's names and the gauge's range are - * appended. - * - * @param root The root element of the result document. - * @param river The river. - * @param gauge The gauge. - * @param context The context object. - */ - protected void appendMetaInformation( - Document doc, - Element root, - River river, - Gauge gauge, - Object context) - { - log.debug("MainValuesService.appendMetaInformation"); - - ElementCreator cr = new ElementCreator( - doc, - ArtifactNamespaceContext.NAMESPACE_URI, - ArtifactNamespaceContext.NAMESPACE_PREFIX); - - Range range = gauge.getRange(); - - Element riverEl = cr.create("river"); - cr.addAttr(riverEl, "name", river.getName()); - - Element gaugeEl = cr.create("gauge"); - cr.addAttr(gaugeEl, "name", gauge.getName()); - cr.addAttr(gaugeEl, "from", range.getA().toString()); - cr.addAttr(gaugeEl, "to", range.getB().toString()); - - root.appendChild(riverEl); - root.appendChild(gaugeEl); - } - - - /** Checks i a main value has an official associated, */ - protected static boolean hasOfficialLine( - NamedMainValue nmv, - Integer riverId - ) { - for (OfficialLine ol: nmv.getOfficialLines()) { - if ( - ol.getWstColumn().getWst().getRiver().getId().equals(riverId) - ) { - return true; - } - } - return false; - } - - - /** Append xml representation of main values to document. */ - protected void appendMainValues( - Document doc, - Element root, - List mainValues, - Integer riverId, - Object context) - { - log.debug("MainValuesService.appendMainValues"); - - ElementCreator cr = new ElementCreator( - doc, - ArtifactNamespaceContext.NAMESPACE_URI, - ArtifactNamespaceContext.NAMESPACE_PREFIX); - - Element list = cr.create("mainvalues"); - - for (MainValue mainValue: mainValues) { - Element newEl = buildMainValueElement( - doc, mainValue, riverId, context); - - if (newEl != null) { - list.appendChild(newEl); - } - } - - root.appendChild(list); - } - - - /** - * This method builds a concrete mainvalue element. This element consists of - * three attributes: the value, its name and its type. - * - * @param doc The owner document. - * @param mainValue The mainvalue. - * @param context The context object. - * - * @return a mainvalue element. - */ - protected Element buildMainValueElement( - Document doc, - MainValue mainValue, - Integer riverId, - Object context) - { - ElementCreator cr = new ElementCreator( - doc, - ArtifactNamespaceContext.NAMESPACE_URI, - ArtifactNamespaceContext.NAMESPACE_PREFIX); - - NamedMainValue namedMainValue = mainValue.getMainValue(); - MainValueType mainValueType = namedMainValue.getType(); - - Element el = cr.create("mainvalue"); - - cr.addAttr(el, "value", mainValue.getValue().toString()); - cr.addAttr(el, "name", namedMainValue.getName()); - cr.addAttr(el, "type", mainValueType.getName()); - if (mainValue.getTimeInterval() != null) { - if (mainValue.getTimeInterval().getStartTime() != null) { - cr.addAttr(el, "starttime", - Long.toString( - mainValue.getTimeInterval().getStartTime().getTime())); - } - if (mainValue.getTimeInterval().getStopTime() != null) { - cr.addAttr(el, "stoptime", - Long.toString( - mainValue.getTimeInterval().getStopTime().getTime())); - } - } - - if (hasOfficialLine(namedMainValue, riverId)) { - cr.addAttr(el, "official", "true"); - } - - return el; - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Tue Jul 24 10:36:18 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Tue Jul 24 10:39:03 2018 +0200 @@ -1586,4 +1586,8 @@ String bundu_bezugswst_auto_event_choice(); String years_general(); + + String bundu_bezugswst_mode_ud(); + + String bundu_bezugswst_validation_range(); } \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Tue Jul 24 10:36:18 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Tue Jul 24 10:39:03 2018 +0200 @@ -846,6 +846,8 @@ bundu = Betrieb und Unterhaltung bundu_bezugswst_fix_choice_title= Fixierungsauswahl bundu_bezugswst_auto_event_choice = Automatische Ereignisauswahl +bundu_bezugswst_mode_ud = UD am Pegel [d/a] +bundu_bezugswst_validation_range = Die Eingabe muss eine Ganzzahl zwischen 0 und 364 sein. chart_settings_export_metadata = Show Meta-Data export_csv_title = Title: diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Tue Jul 24 10:36:18 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Tue Jul 24 10:39:03 2018 +0200 @@ -835,7 +835,7 @@ uinfo_vegetation_zones_from = \u00dcfd von [d/a] uinfo_vegetation_zones_to = \u00dcfd bis [d/a] uinfo_vegetation_zones_validation_empty = Eingabefeld leer. -uinfo_vegetation_zones_validation_range = Werte m\u00fcssen zwischen 0 und 365 liegen. +uinfo_vegetation_zones_validation_range = Werte m\u00fcssen zwischen 0 und 365 liegen. uinfo_vegetation_zones_validation_from_greater_to = Der Wert f\u00fcr "\u00dcfd von" muss kleiner als "\u00dcfd bis". uinfo_salix_km_limit_exceed = Die Zahl ist au\u00dferhalb des g\u00fcltigen km-Bereichs. uinfo_salix_km_overlap = Km-Bereiche \u00fcberlappen. @@ -846,6 +846,8 @@ bundu = Betrieb und Unterhaltung bundu_bezugswst_fix_choice_title= Fixierungsauswahl bundu_bezugswst_auto_event_choice = Automatische Ereignisauswahl +bundu_bezugswst_mode_ud = UD am Pegel [d/a] +bundu_bezugswst_validation_range = Die Eingabe muss eine Ganzzahl zwischen 0 und 364 sein. chart_settings_export_metadata = Metadaten anzeigen export_csv_title = Titel: diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesService.java Tue Jul 24 10:39:03 2018 +0200 @@ -0,0 +1,29 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * 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.client.client.services; + +import org.dive4elements.river.client.shared.exceptions.ServerException; +import org.dive4elements.river.client.shared.model.WQInfoObject; + +import com.google.gwt.user.client.rpc.RemoteService; +import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; + +/** + * This service is used to fetch a list dynamically computed main values. + * + * @author Raimund Renkert + */ +@RemoteServiceRelativePath("dynamic-mainvalues") +public interface DynamicMainValuesService extends RemoteService { + + /** + * This method returns a list of DistanceInfoObjects for a specific river. + */ + WQInfoObject[] getWQInfo(String locale, String river, double start, double end, int startYear, int endYear) throws ServerException; +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesServiceAsync.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/services/DynamicMainValuesServiceAsync.java Tue Jul 24 10:39:03 2018 +0200 @@ -0,0 +1,21 @@ +/** 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.client.client.services; + +import org.dive4elements.river.client.shared.model.WQInfoObject; + +import com.google.gwt.user.client.rpc.AsyncCallback; + +/** + * @author Domenico Nardi Tironi + */ +public interface DynamicMainValuesServiceAsync { + void getWQInfo(String locale, String river, double start, double end, int startYear, int endYear, AsyncCallback callback); +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java Tue Jul 24 10:36:18 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java Tue Jul 24 10:39:03 2018 +0200 @@ -248,6 +248,7 @@ * @return the Data with the name name. */ protected Data getData(final List data, final String name) { + for (final Data d : data) { if (name.equals(d.getLabel())) { return d; diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java Tue Jul 24 10:39:03 2018 +0200 @@ -0,0 +1,511 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * 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.client.client.ui; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.dive4elements.river.client.client.Config; +import org.dive4elements.river.client.client.FLYSConstants; +import org.dive4elements.river.client.client.ui.wq.QDTable; +import org.dive4elements.river.client.client.ui.wq.WTable; +import org.dive4elements.river.client.shared.model.ArtifactDescription; +import org.dive4elements.river.client.shared.model.Data; +import org.dive4elements.river.client.shared.model.DataItem; +import org.dive4elements.river.client.shared.model.DataList; +import org.dive4elements.river.client.shared.model.DefaultData; +import org.dive4elements.river.client.shared.model.DefaultDataItem; +import org.dive4elements.river.client.shared.model.WQDataItem; +import org.dive4elements.river.client.shared.model.WQInfoObject; +import org.dive4elements.river.client.shared.model.WQInfoRecord; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.smartgwt.client.data.Record; +import com.smartgwt.client.util.SC; +import com.smartgwt.client.widgets.Canvas; +import com.smartgwt.client.widgets.Label; +import com.smartgwt.client.widgets.form.DynamicForm; +import com.smartgwt.client.widgets.form.fields.events.BlurEvent; +import com.smartgwt.client.widgets.form.fields.events.BlurHandler; +import com.smartgwt.client.widgets.form.fields.events.ChangeEvent; +import com.smartgwt.client.widgets.form.fields.events.ChangeHandler; +import com.smartgwt.client.widgets.grid.events.CellClickEvent; +import com.smartgwt.client.widgets.grid.events.CellClickHandler; +import com.smartgwt.client.widgets.layout.HLayout; +import com.smartgwt.client.widgets.layout.VLayout; +import com.smartgwt.client.widgets.tab.TabSet; + +/** + * This UIProvider creates a widget to enter W or Q data for discharge + * longitudinal section computations. + * + * @author Ingo Weinzierl + */ +abstract public class AbstractWQAdaptedInputPanel extends AbstractUIProvider implements ChangeHandler, BlurHandler { + private static final long serialVersionUID = -3218827566805476423L; + + /** The message class that provides i18n strings. */ + protected FLYSConstants MSG = GWT.create(FLYSConstants.class); + protected static final int ROW_HEIGHT = 20; + + /** List of QDTables in inputhelper section. */ + protected List qdTables; + + private static final String GAUGE_SEPARATOR = ":"; + + private static final String GAUGE_PART_SEPARATOR = ";"; + + private static final String VALUE_SEPARATOR = ","; + + /** Stores the input panels related to their keys. */ + protected Map wqranges; + + /** [startkm,endkm] per gauge in selected range. */ + protected List gaugeRanges; + + /** Stores the min/max values for each q range (gauge). */ + protected Map qranges; + + /** The RadioGroupItem that determines the w/q input mode. */ + protected DynamicForm modes; + /** List of doubleArrayPanels shown. */ + protected final ArrayList doubleArrayPanels = new ArrayList(); + /** List of wTables in inputhelper section. */ + protected List wTables; + + /** Tabs in inputhelper area. */ + protected TabSet tabs; + + public AbstractWQAdaptedInputPanel() { + this.wqranges = new HashMap(); + this.qranges = new HashMap(); + this.wTables = new ArrayList(); + this.qdTables = new ArrayList(); + } + + /** Inits the helper panel. */ + // TODO duplicate in WQInputPanel + protected void initHelperPanel() { + this.tabs = new TabSet(); + this.tabs.setWidth100(); + this.tabs.setHeight100(); + + // For each gauge, add two tabs with helper tables. + createTabs(); + + this.helperContainer.addMember(this.tabs); + } + + /** Create labels, canvasses, layouts. */ + @Override + public Canvas create(final DataList data) { + beforeCreate(data); + + readGaugeRanges(data); + initHelperPanel(); + + final Canvas submit = getNextButton(); + final Canvas widget = createWidget(data); + final Label label = new Label(this.MSG.wqadaptedTitle()); + + label.setHeight(25); + + final VLayout layout = new VLayout(); + layout.setMembersMargin(10); + layout.setWidth(350); + + layout.addMember(label); + layout.addMember(widget); + layout.addMember(submit); + + fetchWQData(); + + initTableListeners(); + + afterCreate(); + + return layout; + } + + protected abstract void createTabs(); + + protected abstract void beforeCreate(final DataList data); + + protected abstract void afterCreate(); + + /** + * Initializes the listeners of the WQD tables. + */ + // TODO dupe from WQInputPanel + protected void initTableListeners() { + int i = 0; + for (final QDTable qdTable : this.qdTables) { + // Register listener such that values are filled in on click. + final QDTable table = qdTable; + final int fi = i; + final CellClickHandler handler = new CellClickHandler() { + @Override + public void onCellClick(final CellClickEvent e) { + if (table.isDisabled() || table.isLocked()) { + return; + } + + final Record r = e.getRecord(); + final double val = r.getAttributeAsDouble("value"); + + AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi).setValues(new double[] { val }); + // If a named value for first gauge is chosen, + // try to find and set + // the values to the other panels too. + if (fi == 0) { + final String valueName = r.getAttribute("name"); + int oi = 0; + // TODO instead of oi use random access. + for (final QDTable otherQDTable : AbstractWQAdaptedInputPanel.this.qdTables) { + if (oi == 0) { + oi++; + continue; + } + final Double value = otherQDTable.findRecordValue(valueName); + if (value == null) { + SC.warn(AbstractWQAdaptedInputPanel.this.MSG.noMainValueAtGauge()); + } else { + AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(oi).setValues(new double[] { value }); + } + oi++; + } + } else { + // Focus next. + if (fi != AbstractWQAdaptedInputPanel.this.doubleArrayPanels.size() - 1) { + AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi + 1).focusInItem(1); + } + } + } + }; + + qdTable.addCellClickHandler(handler); + i++; + } + + i = 0; + for (final WTable wTable : this.wTables) { + // Register listener such that values are filled in on click. + final WTable table = wTable; + final int fi = i; + final CellClickHandler handler = new CellClickHandler() { + + @Override + public void onCellClick(final CellClickEvent e) { + if (table.isDisabled()) { + return; + } + + final Record r = e.getRecord(); + final double val = r.getAttributeAsDouble("value"); + + AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi).setValues(new double[] { val }); + // If a named value for first gauge is chosen, + // try to find and set + // the values to the other panels too. + if (fi == 0) { + final String valueName = r.getAttribute("name"); + int oi = 0; + // TODO instead of oi use random access. + for (final WTable otherWTable : AbstractWQAdaptedInputPanel.this.wTables) { + if (oi == 0) { + oi++; + continue; + } + final Double value = otherWTable.findRecordValue(valueName); + if (value == null) { + // TODO: afterwards it freaks out + SC.warn(AbstractWQAdaptedInputPanel.this.MSG.noMainValueAtGauge()); + } else { + AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(oi).setValues(new double[] { value }); + } + oi++; + } + } else { + // Focus next. + if (fi != AbstractWQAdaptedInputPanel.this.doubleArrayPanels.size() - 1) { + AbstractWQAdaptedInputPanel.this.doubleArrayPanels.get(fi + 1).focusInItem(1); + } + } + } + + }; + + wTable.addCellClickHandler(handler); + i++; + } + } + + /** Create area showing previously entered w or q data. */ + protected final Canvas createOldWQValues(final Data wqData, final boolean isQ) { + + final VLayout layout = new VLayout(); + if (wqData != null) { + final DataItem item = wqData.getItems()[0]; + final String value = item.getStringValue(); + + final String[] gauges = value.split(GAUGE_SEPARATOR); + + final String unit = isQ ? "m³/s" : "cm"; + + for (final String gauge : gauges) { + final HLayout h = new HLayout(); + + final String[] parts = gauge.split(GAUGE_PART_SEPARATOR); + final String[] values = parts[3].split(VALUE_SEPARATOR); + + final Label l = new Label(parts[2] + ": "); + + final StringBuilder sb = new StringBuilder(); + boolean first = true; + + for (final String v : values) { + if (!first) { + sb.append(", "); + } + + sb.append(v); + sb.append(" "); + sb.append(unit); + + first = false; + } + + final Label v = new Label(sb.toString()); + + l.setWidth(65); + v.setWidth(65); + + h.addMember(l); + h.addMember(v); + + layout.addMember(h); + } + } + + return layout; + } + + protected void initUserWQValues(final DataList dataList) { + final List allData = dataList.getAll(); + + final Data dDef = getData(allData, "wq_values"); + final DataItem def = dDef != null ? dDef.getDefault() : null; + final String value = def != null ? def.getStringValue() : null; + + if (value == null || value.length() == 0) { + return; + } + + final String[] lines = value.split(GAUGE_SEPARATOR); + + if (lines == null || lines.length == 0) { + return; + } + + for (final String line : lines) { + final String[] cols = line.split(GAUGE_PART_SEPARATOR); + // final String title = createLineTitle(line); + + if (cols == null || cols.length < 3) { + continue; + } + + final String[] strValues = cols[2].split(VALUE_SEPARATOR); + final double[] values = new double[strValues.length]; + + int idx = 0; + + for (final String strValue : strValues) { + try { + values[idx++] = Double.valueOf(strValue); + } + catch (final NumberFormatException nfe) { + // do nothing + } + } + + final String key = cols[0] + GAUGE_PART_SEPARATOR + cols[1]; + final DoubleArrayPanel dap = this.wqranges.get(key); + + if (dap == null) { + continue; + } + + dap.setValues(values); + } + } + + /** Populate Gauge Ranges array. */ + protected final void readGaugeRanges(final DataList dataList) { + final List items = getWQItems(dataList); + this.gaugeRanges = new ArrayList(); + + for (final DataItem item : items) { + if (item instanceof WQDataItem) { + final String[] startEndKm = item.getLabel().split(";"); + final Double[] kvp = new Double[] { Double.parseDouble(startEndKm[0]), Double.parseDouble(startEndKm[1]) }; + this.gaugeRanges.add(kvp); + } + } + } + + /** Get items which are not WQ_MODE. */ + protected List getWQItems(final DataList dataList) { + final List data = dataList.getAll(); + final List results = new ArrayList(); + for (final Data d : data) { + final DataItem[] items = d.getItems(); + if (items != null) { + for (final Object item : items) { + if (item instanceof WQDataItem) + results.add((WQDataItem) item); + } + } + } + return results; + } + + protected final Data getWQValues(final String dataKey) { + String wqvalue = null; + + for (final Map.Entry entry : this.wqranges.entrySet()) { + final String key = entry.getKey(); + final DoubleArrayPanel dap = entry.getValue(); + final String label = dap.getItemTitle(); + + final double[] values = dap.getInputValues(); + if (wqvalue == null) { + wqvalue = createValueString(key + ";" + label, values); + } else { + wqvalue += GAUGE_SEPARATOR + createValueString(key + ";" + label, values); + } + } + + final DataItem valueItem = new DefaultDataItem(dataKey, dataKey, wqvalue); + final Data values = new DefaultData(dataKey, null, null, new DataItem[] { valueItem }); + + return values; + } + + protected String createValueString(final String key, final double[] values) { + final StringBuilder sb = new StringBuilder(); + + boolean first = true; + + for (final double value : values) { + if (!first) { + sb.append(","); + } + + sb.append(Double.toString(value)); + + first = false; + } + + return key + ";" + sb.toString(); + } + + @Override + public void onChange(final ChangeEvent event) { + // TODO IMPLEMENT ME + } + + /** Store the currently focussed DoubleArrayPanel and focus helper tab. */ + + @Override + public final void onBlur(final BlurEvent event) { + final DoubleArrayPanel dap = (DoubleArrayPanel) event.getForm(); + dap.validateForm(event.getItem()); + } + + /** Get the WQD data from service and stuck them up that tables. */ + protected void fetchWQData() { + final Config config = Config.getInstance(); + final String locale = config.getLocale(); + + final ArtifactDescription adescr = this.artifact.getArtifactDescription(); + final DataList[] data = adescr.getOldData(); + + final String river = getRiverName(data); + + int i = 0; + + // Get Data for respective gauge. + for (final Double[] range : this.gaugeRanges) { + // Gauge ranges overlap, move start and end a bit closer + // to each other. + final double rDiff = (range[1] - range[0]) / 10d; + final int fi = i; + + final AsyncCallback cb = new AsyncCallback() { + @Override + public void onFailure(final Throwable caught) { + GWT.log("Could not recieve wq informations."); + SC.warn(caught.getMessage()); + } + + @Override + public void onSuccess(final WQInfoObject[] wqi) { + final int num = wqi != null ? wqi.length : 0; + GWT.log("Received " + num + " wq informations (" + fi + "."); + + if (num == 0) { + return; + } + + addWQInfo(wqi, fi); + } + }; + + callMainValuesService(locale, river, range[0] + rDiff, range[1] - rDiff, cb); + + i++; + } + } + + protected abstract void callMainValuesService(String locale, String river, double start, double end, AsyncCallback cb); + + /** Add Info to helper table for gauge at index gaugeIdx. */ + private void addWQInfo(final WQInfoObject[] wqi, final int gaugeIdx) { + for (final WQInfoObject wi : wqi) { + final WQInfoRecord rec = new WQInfoRecord(wi); + + if (wi.getType().equals("W")) { + if (gaugeIdx < this.wTables.size()) + this.wTables.get(gaugeIdx).addData(rec); + } else if (wi.getType().equals("Q")) { + if (gaugeIdx < this.qdTables.size()) + this.qdTables.get(gaugeIdx).addData(rec); + } + } + } + + /** + * Returns the name of the selected river. + * + * @param data + * The DataList with all data. + * + * @return the name of the current river. + */ + protected String getRiverName(final DataList[] data) { + final ArtifactDescription adesc = this.artifact.getArtifactDescription(); + return adesc.getRiver(); + } + + abstract protected Canvas createWidget(final DataList dataList); +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WQAdaptedInputPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WQAdaptedInputPanel.java Tue Jul 24 10:36:18 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WQAdaptedInputPanel.java Tue Jul 24 10:39:03 2018 +0200 @@ -14,13 +14,10 @@ import java.util.List; import java.util.Map; -import org.dive4elements.river.client.client.Config; -import org.dive4elements.river.client.client.FLYSConstants; import org.dive4elements.river.client.client.services.WQInfoService; import org.dive4elements.river.client.client.services.WQInfoServiceAsync; import org.dive4elements.river.client.client.ui.wq.QDTable; import org.dive4elements.river.client.client.ui.wq.WTable; -import org.dive4elements.river.client.shared.model.ArtifactDescription; import org.dive4elements.river.client.shared.model.Data; import org.dive4elements.river.client.shared.model.DataItem; import org.dive4elements.river.client.shared.model.DataList; @@ -28,12 +25,10 @@ import org.dive4elements.river.client.shared.model.DefaultDataItem; import org.dive4elements.river.client.shared.model.WQDataItem; import org.dive4elements.river.client.shared.model.WQInfoObject; -import org.dive4elements.river.client.shared.model.WQInfoRecord; import com.google.gwt.core.client.GWT; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.user.client.rpc.AsyncCallback; -import com.smartgwt.client.data.Record; import com.smartgwt.client.types.TitleOrientation; import com.smartgwt.client.types.VerticalAlignment; import com.smartgwt.client.util.SC; @@ -41,18 +36,13 @@ import com.smartgwt.client.widgets.Label; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.fields.RadioGroupItem; -import com.smartgwt.client.widgets.form.fields.events.BlurEvent; -import com.smartgwt.client.widgets.form.fields.events.BlurHandler; import com.smartgwt.client.widgets.form.fields.events.ChangeEvent; import com.smartgwt.client.widgets.form.fields.events.ChangeHandler; import com.smartgwt.client.widgets.form.fields.events.FocusEvent; import com.smartgwt.client.widgets.form.fields.events.FocusHandler; -import com.smartgwt.client.widgets.grid.events.CellClickEvent; -import com.smartgwt.client.widgets.grid.events.CellClickHandler; import com.smartgwt.client.widgets.layout.HLayout; import com.smartgwt.client.widgets.layout.VLayout; import com.smartgwt.client.widgets.tab.Tab; -import com.smartgwt.client.widgets.tab.TabSet; /** * This UIProvider creates a widget to enter W or Q data for discharge @@ -60,257 +50,204 @@ * * @author Ingo Weinzierl */ -public class WQAdaptedInputPanel extends AbstractUIProvider implements ChangeHandler, BlurHandler, FocusHandler { +public class WQAdaptedInputPanel extends AbstractWQAdaptedInputPanel implements FocusHandler { private static final long serialVersionUID = -3218827566805476423L; - - /** The message class that provides i18n strings. */ - protected FLYSConstants MESSAGE = GWT.create(FLYSConstants.class); - - public static final String FIELD_WQ_MODE = "wq_isq"; - public static final String FIELD_WQ_W = "W"; - public static final String FIELD_WQ_Q = "Q"; - - public static final String GAUGE_SEPARATOR = ":"; - - public static final String GAUGE_PART_SEPARATOR = ";"; - - public static final String VALUE_SEPARATOR = ","; - - public static final int ROW_HEIGHT = 20; - - /** The constant field name for choosing w or q mode. */ - public static final String FIELD_WQ = "wq"; - - /** The constant field name for choosing single values or range. */ - public static final String FIELD_MODE = "mode"; - - /** The constant field value for range input mode. */ - public static final String FIELD_MODE_RANGE = "range"; - - /** Service to fetch W/Q MainValues. */ - protected WQInfoServiceAsync wqInfoService = GWT.create(WQInfoService.class); - - /** The message class that provides i18n strings. */ - protected FLYSConstants MSG = GWT.create(FLYSConstants.class); - - /** Stores the input panels related to their keys. */ - protected Map wqranges; - - /** List of doubleArrayPanels shown. */ - protected ArrayList doubleArrayPanels; - - /** [startkm,endkm] per gauge in selected range. */ - protected List gaugeRanges; - - /** Stores the min/max values for each q range (gauge). */ - protected Map qranges; + private static final String FIELD_WQ_MODE = "wq_isq"; + private static final String FIELD_WQ_W = "W"; + private static final String FIELD_WQ_Q = "Q"; /** Stores the min/max values for each w range (gauge). */ - protected Map wranges; - - /** The RadioGroupItem that determines the w/q input mode. */ - protected DynamicForm modes; + private final Map wranges = new HashMap(); - /** List of wTables in inputhelper section. */ - protected List wTables; - - /** List of QDTables in inputhelper section. */ - protected List qdTables; - - /** Tabs in inputhelper area. */ - protected TabSet tabs; + /** Service to fetch W/Q MainValues. */ + private final WQInfoServiceAsync wqInfoService = GWT.create(WQInfoService.class); /** The currently focussed Input element. */ - protected DoubleArrayPanel itemWithFocus; + private DoubleArrayPanel itemWithFocus; - public WQAdaptedInputPanel() { - this.wqranges = new HashMap(); - this.doubleArrayPanels = new ArrayList(); - this.qranges = new HashMap(); - this.wranges = new HashMap(); - this.wTables = new ArrayList(); - this.qdTables = new ArrayList(); + private void enableWTabs() { + for (int i = 0; i < this.doubleArrayPanels.size(); i++) { + this.tabs.disableTab(2 * i); + this.tabs.enableTab(2 * i + 1); + } } - /** Create labels, canvasses, layouts. */ - @Override - public Canvas create(final DataList data) { - readGaugeRanges(data); - initHelperPanel(); - - final Canvas submit = getNextButton(); - final Canvas widget = createWidget(data); - final Label label = new Label(this.MSG.wqadaptedTitle()); - - label.setHeight(25); + private void enableQTabs() { + for (int i = 0; i < this.doubleArrayPanels.size(); i++) { + this.tabs.enableTab(2 * i); + this.tabs.disableTab(2 * i + 1); + } + } - final VLayout layout = new VLayout(); - layout.setMembersMargin(10); - layout.setWidth(350); + /** + * Create radio button for switching w and q input. + * Radiobutton-change also triggers helper panel tab selection. + */ - layout.addMember(label); - layout.addMember(widget); - layout.addMember(submit); + private final Canvas createMode(final DataList dataList) { + final RadioGroupItem wq = new RadioGroupItem(FIELD_WQ_MODE); + wq.setShowTitle(false); + wq.setVertical(false); + wq.setWidth(200); - fetchWQData(); + final LinkedHashMap wqValues = new LinkedHashMap(); + wqValues.put(FIELD_WQ_W, this.MSG.wqW()); + wqValues.put(WQAdaptedInputPanel.FIELD_WQ_Q, this.MSG.wqQatGauge()); - initTableListeners(); + wq.setValueMap(wqValues); + this.modes = new DynamicForm(); + this.modes.setFields(wq); + this.modes.setWidth(200); + wq.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(final ChangeEvent e) { + final DynamicForm form = e.getForm(); + + if (form.getValueAsString(FIELD_WQ_MODE).contains("Q")) { + WQAdaptedInputPanel.this.tabs.selectTab(0); + enableQTabs(); + } else { + WQAdaptedInputPanel.this.tabs.selectTab(1); + enableWTabs(); + } + } + }); + + final LinkedHashMap initial = new LinkedHashMap(); + initial.put(FIELD_WQ_MODE, this.FIELD_WQ_Q); + this.modes.setValues(initial); + this.tabs.selectTab(1); + return this.modes; + } + + @Override + protected void createTabs() { + for (int i = 0; i < this.gaugeRanges.size(); i++) { + // Later the tabs title will get adjusted to include gauges name. + // TODO the tabs title becomes rather long through that (i18n). + + final Tab wTab = new Tab(this.MSG.wq_table_w()); + final WTable wTable = new WTable(); + this.wTables.add(wTable); + wTable.showSelect(); + wTab.setPane(wTable); + + final Tab qTab = new Tab(this.MSG.wq_table_q()); + final QDTable qdTable = new QDTable(); + this.qdTables.add(qdTable); + qTab.setPane(qdTable); + qdTable.showSelect(); + + this.tabs.addTab(wTab, i * 2 + 0); + this.tabs.addTab(qTab, i * 2 + 1); + + } + + // Defaults at "Q", first input field. + this.tabs.selectTab(0); + enableQTabs(); + } + + @Override + protected void beforeCreate(final DataList data) { + } + + @Override + protected void afterCreate() { // We actually want the first Q tab to be selected and all // Q tabs to be enabled. I sense a bug in TabSet here, as // the code in the W/Q radiogroup-changehandler behaves // exactly vice versa (enabling Q, selecting tab 0). enableWTabs(); this.tabs.selectTab(1); + } + + @Override + protected Canvas createWidget(final DataList dataList) { + final VLayout layout = new VLayout(); + final Canvas mode = createMode(dataList); + final Canvas list = createList(dataList); + + final List items = getWQItems(dataList); + final int listHeight = ROW_HEIGHT * items.size(); + + mode.setHeight(25); + mode.setWidth(200); + + layout.addMember(mode); + layout.addMember(list); + + layout.setHeight(25 + listHeight); + layout.setWidth(350); + + initUserDefaults(dataList); return layout; } - /** Inits the helper panel. */ - // TODO duplicate in WQInputPanel - protected void initHelperPanel() { - this.tabs = new TabSet(); - this.tabs.setWidth100(); - this.tabs.setHeight100(); - - // For each gauge, add two tabs with helper tables. - - for (int i = 0; i < this.gaugeRanges.size(); i++) { - // Later the tabs title will get adjusted to include gauges name. - // TODO the tabs title becomes rather long through that (i18n). - final Tab wTab = new Tab(this.MESSAGE.wq_table_w()); - final Tab qTab = new Tab(this.MESSAGE.wq_table_q()); - - final QDTable qdTable = new QDTable(); - final WTable wTable = new WTable(); - - this.wTables.add(wTable); - this.qdTables.add(qdTable); - - qdTable.showSelect(); - wTable.showSelect(); - wTab.setPane(wTable); - qTab.setPane(qdTable); - - this.tabs.addTab(wTab, i * 2 + 0); - this.tabs.addTab(qTab, i * 2 + 1); - // tabs.disableTab(i*2+1); - } - - // Defaults at "Q", first input field. - this.tabs.selectTab(0); - enableQTabs(); - - this.helperContainer.addMember(this.tabs); + private void initUserDefaults(final DataList dataList) { + initUserWQValues(dataList); + initUserWQMode(dataList); } - /** - * Initializes the listeners of the WQD tables. - */ - // TODO dupe from WQInputPanel - protected void initTableListeners() { - int i = 0; - for (final QDTable qdTable : this.qdTables) { - // Register listener such that values are filled in on click. - final QDTable table = qdTable; - final int fi = i; - final CellClickHandler handler = new CellClickHandler() { - @Override - public void onCellClick(final CellClickEvent e) { - if (isWMode() || table.isLocked()) { - return; - } - - final Record r = e.getRecord(); - final double val = r.getAttributeAsDouble("value"); - - WQAdaptedInputPanel.this.doubleArrayPanels.get(fi).setValues(new double[] { val }); - // If a named value for first gauge is chosen, - // try to find and set - // the values to the other panels too. - if (fi == 0) { - final String valueName = r.getAttribute("name"); - int oi = 0; - // TODO instead of oi use random access. - for (final QDTable otherQDTable : WQAdaptedInputPanel.this.qdTables) { - if (oi == 0) { - oi++; - continue; - } - final Double value = otherQDTable.findRecordValue(valueName); - if (value == null) { - SC.warn(WQAdaptedInputPanel.this.MSG.noMainValueAtGauge()); - } else { - WQAdaptedInputPanel.this.doubleArrayPanels.get(oi).setValues(new double[] { value }); - } - oi++; - } - } else { - // Focus next. - if (fi != WQAdaptedInputPanel.this.doubleArrayPanels.size() - 1) { - WQAdaptedInputPanel.this.doubleArrayPanels.get(fi + 1).focusInItem(1); - } - } - } - }; + private void initUserWQMode(final DataList dataList) { + final List allData = dataList.getAll(); - qdTable.addCellClickHandler(handler); - i++; - } - - i = 0; - for (final WTable wTable : this.wTables) { - // Register listener such that values are filled in on click. - final WTable table = wTable; - final int fi = i; - final CellClickHandler handler = new CellClickHandler() { - @Override - public void onCellClick(final CellClickEvent e) { - if (!isWMode() /* || table.isLocked() */) { - return; - } - - final Record r = e.getRecord(); - final double val = r.getAttributeAsDouble("value"); + final Data dDef = getData(allData, "wq_mode"); + final DataItem def = dDef != null ? dDef.getDefault() : null; + final String value = def != null ? def.getStringValue() : null; - WQAdaptedInputPanel.this.doubleArrayPanels.get(fi).setValues(new double[] { val }); - // If a named value for first gauge is chosen, - // try to find and set - // the values to the other panels too. - if (fi == 0) { - final String valueName = r.getAttribute("name"); - int oi = 0; - // TODO instead of oi use random access. - for (final WTable otherWTable : WQAdaptedInputPanel.this.wTables) { - if (oi == 0) { - oi++; - continue; - } - final Double value = otherWTable.findRecordValue(valueName); - if (value == null) { - // TODO: afterwards it freaks out - SC.warn(WQAdaptedInputPanel.this.MSG.noMainValueAtGauge()); - } else { - WQAdaptedInputPanel.this.doubleArrayPanels.get(oi).setValues(new double[] { value }); - } - oi++; - } - } else { - // Focus next. - if (fi != WQAdaptedInputPanel.this.doubleArrayPanels.size() - 1) { - WQAdaptedInputPanel.this.doubleArrayPanels.get(fi + 1).focusInItem(1); - } - } - } - }; - - wTable.addCellClickHandler(handler); - i++; + if (value != null && value.equals(FIELD_WQ_W)) { + this.modes.setValue(FIELD_WQ_MODE, FIELD_WQ_W); + } else { + this.modes.setValue(FIELD_WQ_MODE, FIELD_WQ_Q); } } + private Canvas createList(final DataList dataList) { + final VLayout layout = new VLayout(); + + final List items = getWQItems(dataList); + + int i = 0; + + for (final DataItem item : items) { + if (item instanceof WQDataItem) { + final String title = item.getLabel(); // of form: 70.5;112.0 + final String label = item.getStringValue(); + + // Rename W and Q tab to include gauges name. + this.tabs.getTab(i * 2).setTitle(this.tabs.getTab(i * 2).getTitle() + " (" + label + ")"); + this.tabs.getTab(i * 2 + 1).setTitle(this.tabs.getTab(i * 2 + 1).getTitle() + " (" + label + ")"); + + final DoubleArrayPanel dap = new DoubleArrayPanel(label, null, this, this, TitleOrientation.LEFT); + + this.wqranges.put(title, dap); + this.doubleArrayPanels.add(dap); + + if (item instanceof WQDataItem) { + final WQDataItem wq = (WQDataItem) item; + final double[] mmQ = wq.getQRange(); + final double[] mmW = wq.getWRange(); + + this.qranges.put(title, mmQ); + this.wranges.put(title, mmW); + } + + layout.addMember(dap); + i++; + } + + } + + layout.setHeight(items.size() * ROW_HEIGHT); + + return layout; + } + @Override - public Canvas createOld(final DataList dataList) { + public Canvas createOld(final DataList dataList) { // TODO: OVERRIDE final List all = dataList.getAll(); final Data wqData = getData(all, "wq_values"); final Data wqMode = getData(all, "wq_isq"); @@ -343,78 +280,6 @@ return vlayout; } - /** Create area showing previously entered w or q data. */ - protected Canvas createOldWQValues(final Data wqData, final boolean isQ) { - final VLayout layout = new VLayout(); - - final DataItem item = wqData.getItems()[0]; - final String value = item.getStringValue(); - - final String[] gauges = value.split(GAUGE_SEPARATOR); - - final String unit = isQ ? "m³/s" : "cm"; - - for (final String gauge : gauges) { - final HLayout h = new HLayout(); - - final String[] parts = gauge.split(GAUGE_PART_SEPARATOR); - final String[] values = parts[3].split(VALUE_SEPARATOR); - - final Label l = new Label(parts[2] + ": "); - - final StringBuilder sb = new StringBuilder(); - boolean first = true; - - for (final String v : values) { - if (!first) { - sb.append(", "); - } - - sb.append(v); - sb.append(" "); - sb.append(unit); - - first = false; - } - - final Label v = new Label(sb.toString()); - - l.setWidth(65); - v.setWidth(65); - - h.addMember(l); - h.addMember(v); - - layout.addMember(h); - } - - return layout; - } - - /** Create non-input helper part of the UI. */ - protected Canvas createWidget(final DataList dataList) { - final VLayout layout = new VLayout(); - - final Canvas mode = createMode(dataList); - final Canvas list = createList(dataList); - - final DataItem[] items = getWQItems(dataList); - final int listHeight = ROW_HEIGHT * items.length; - - mode.setHeight(25); - mode.setWidth(200); - - layout.addMember(mode); - layout.addMember(list); - - layout.setHeight(25 + listHeight); - layout.setWidth(350); - - initUserDefaults(dataList); - - return layout; - } - @Override public List validate() { if (isWMode()) { @@ -424,6 +289,12 @@ } } + private boolean isWMode() { + final String mode = (String) this.modes.getValue(FIELD_WQ_MODE); + + return FIELD_WQ_W.equals(mode); + } + protected List validateRange(final Map ranges) { final List errors = new ArrayList(); final NumberFormat nf = NumberFormat.getDecimalFormat(); @@ -477,233 +348,7 @@ return errors; } - protected List validateW() { - return validateRange(this.wranges); - } - - protected List validateQ() { - return validateRange(this.qranges); - } - - protected void initUserDefaults(final DataList dataList) { - initUserWQValues(dataList); - initUserWQMode(dataList); - } - - protected void initUserWQMode(final DataList dataList) { - final List allData = dataList.getAll(); - - final Data dDef = getData(allData, "wq_mode"); - final DataItem def = dDef != null ? dDef.getDefault() : null; - final String value = def != null ? def.getStringValue() : null; - - if (value != null && value.equals(FIELD_WQ_W)) { - this.modes.setValue(FIELD_WQ_MODE, FIELD_WQ_W); - } else { - this.modes.setValue(FIELD_WQ_MODE, FIELD_WQ_Q); - } - } - - protected void initUserWQValues(final DataList dataList) { - final List allData = dataList.getAll(); - - final Data dDef = getData(allData, "wq_values"); - final DataItem def = dDef != null ? dDef.getDefault() : null; - final String value = def != null ? def.getStringValue() : null; - - if (value == null || value.length() == 0) { - return; - } - - final String[] lines = value.split(GAUGE_SEPARATOR); - - if (lines == null || lines.length == 0) { - return; - } - - for (final String line : lines) { - final String[] cols = line.split(GAUGE_PART_SEPARATOR); - final String title = createLineTitle(line); - - if (cols == null || cols.length < 3) { - continue; - } - - final String[] strValues = cols[2].split(VALUE_SEPARATOR); - final double[] values = new double[strValues.length]; - - int idx = 0; - - for (final String strValue : strValues) { - try { - values[idx++] = Double.valueOf(strValue); - } - catch (final NumberFormatException nfe) { - // do nothing - } - } - - final String key = cols[0] + GAUGE_PART_SEPARATOR + cols[1]; - final DoubleArrayPanel dap = this.wqranges.get(key); - - if (dap == null) { - continue; - } - - dap.setValues(values); - } - } - - /** Populate Gauge Ranges array. */ - private void readGaugeRanges(final DataList dataList) { - final DataItem[] items = getWQItems(dataList); - this.gaugeRanges = new ArrayList(); - - int i = 0; - - for (final DataItem item : items) { - if (item instanceof WQDataItem) { - final String[] startEndKm = item.getLabel().split(";"); - final Double[] kvp = new Double[] { Double.parseDouble(startEndKm[0]), Double.parseDouble(startEndKm[1]) }; - this.gaugeRanges.add(kvp); - } - i++; - } - } - - protected Canvas createList(final DataList dataList) { - final VLayout layout = new VLayout(); - - final DataItem[] items = getWQItems(dataList); - - int i = 0; - - for (final DataItem item : items) { - if (item instanceof WQDataItem) { - final String title = item.getLabel(); // of form: 70.5;112.0 - final String label = item.getStringValue(); - - // Rename W and Q tab to include gauges name. - this.tabs.getTab(i * 2).setTitle(this.tabs.getTab(i * 2).getTitle() + " (" + label + ")"); - this.tabs.getTab(i * 2 + 1).setTitle(this.tabs.getTab(i * 2 + 1).getTitle() + " (" + label + ")"); - - final DoubleArrayPanel dap = new DoubleArrayPanel(label, null, this, this, TitleOrientation.LEFT); - - this.wqranges.put(title, dap); - this.doubleArrayPanels.add(dap); - - if (item instanceof WQDataItem) { - final WQDataItem wq = (WQDataItem) item; - final double[] mmQ = wq.getQRange(); - final double[] mmW = wq.getWRange(); - - this.qranges.put(title, mmQ); - this.wranges.put(title, mmW); - } - - layout.addMember(dap); - } - i++; - } - - layout.setHeight(items.length * ROW_HEIGHT); - - return layout; - } - - /** Get items which are not WQ_MODE. */ - protected DataItem[] getWQItems(final DataList dataList) { - final List data = dataList.getAll(); - - for (final Data d : data) { - final String name = d.getLabel(); - - if (name.equals(FIELD_WQ_MODE) || name.startsWith("ignore_")) { - continue; - } - - return d.getItems(); - } - - return null; - } - - /** - * Create radio button for switching w and q input. - * Radiobutton-change also triggers helper panel tab selection. - */ - protected Canvas createMode(final DataList dataList) { - final RadioGroupItem wq = new RadioGroupItem(FIELD_WQ_MODE); - wq.setShowTitle(false); - wq.setVertical(false); - wq.setWidth(200); - - final LinkedHashMap wqValues = new LinkedHashMap(); - wqValues.put(FIELD_WQ_W, this.MSG.wqW()); - wqValues.put(FIELD_WQ_Q, this.MSG.wqQatGauge()); - - wq.setValueMap(wqValues); - - this.modes = new DynamicForm(); - this.modes.setFields(wq); - this.modes.setWidth(200); - wq.addChangeHandler(new ChangeHandler() { - @Override - public void onChange(final ChangeEvent e) { - final DynamicForm form = e.getForm(); - - if (form.getValueAsString(FIELD_WQ_MODE).contains("Q")) { - WQAdaptedInputPanel.this.tabs.selectTab(0); - enableQTabs(); - } else { - WQAdaptedInputPanel.this.tabs.selectTab(1); - enableWTabs(); - } - } - }); - - final LinkedHashMap initial = new LinkedHashMap(); - initial.put(FIELD_WQ_MODE, FIELD_WQ_Q); - this.modes.setValues(initial); - this.tabs.selectTab(1); - return this.modes; - } - - public void enableWTabs() { - for (int i = 0; i < this.doubleArrayPanels.size(); i++) { - this.tabs.disableTab(2 * i); - this.tabs.enableTab(2 * i + 1); - } - } - - public void enableQTabs() { - for (int i = 0; i < this.doubleArrayPanels.size(); i++) { - this.tabs.enableTab(2 * i); - this.tabs.disableTab(2 * i + 1); - } - } - - public String createLineTitle(final String key) { - final String[] splitted = key.split(";"); - - return splitted[0] + " - " + splitted[1]; - } - - @Override - public Data[] getData() { - final Data mode = getWQMode(); - final Data values = getWQValues(); - - return new Data[] { mode, values }; - } - - public boolean isWMode() { - final String mode = (String) this.modes.getValue(FIELD_WQ_MODE); - - return FIELD_WQ_W.equals(mode); - } - - protected Data getWQMode() { + private Data getWQMode() { final String wqMode = this.modes.getValueAsString(FIELD_WQ_MODE); String value = "false"; if (wqMode.equals("Q")) { @@ -715,52 +360,22 @@ return mode; } - protected Data getWQValues() { - String wqvalue = null; - - for (final Map.Entry entry : this.wqranges.entrySet()) { - final String key = entry.getKey(); - final DoubleArrayPanel dap = entry.getValue(); - final String label = dap.getItemTitle(); + @Override + public Data[] getData() { + final Data mode = getWQMode(); + final Data values = getWQValues("wq_values"); - final double[] values = dap.getInputValues(); - if (wqvalue == null) { - wqvalue = createValueString(key + ";" + label, values); - } else { - wqvalue += GAUGE_SEPARATOR + createValueString(key + ";" + label, values); - } - } - - final DataItem valueItem = new DefaultDataItem("wq_values", "wq_values", wqvalue); - final Data values = new DefaultData("wq_values", null, null, new DataItem[] { valueItem }); - - return values; + return new Data[] { mode, values }; } - protected String createValueString(final String key, final double[] values) { - final StringBuilder sb = new StringBuilder(); - - boolean first = true; - - for (final double value : values) { - if (!first) { - sb.append(","); - } - - sb.append(Double.toString(value)); - - first = false; - } - - return key + ";" + sb.toString(); + private List validateW() { + return validateRange(this.wranges); } - @Override - public void onChange(final ChangeEvent event) { - // TODO IMPLEMENT ME + private List validateQ() { + return validateRange(this.qranges); } - /** Store the currently focussed DoubleArrayPanel and focus helper tab. */ @Override public void onFocus(final FocusEvent event) { this.itemWithFocus = (DoubleArrayPanel) event.getForm(); @@ -771,93 +386,8 @@ } @Override - public void onBlur(final BlurEvent event) { - final DoubleArrayPanel dap = (DoubleArrayPanel) event.getForm(); - dap.validateForm(event.getItem()); + protected void callMainValuesService(final String locale, final String river, final double start, final double end, + final AsyncCallback cb) { + this.wqInfoService.getWQInfo(locale, river, start, end, cb); } - - /** Get the WQD data from service and stuck them up that tables. */ - protected void fetchWQData() { - final Config config = Config.getInstance(); - final String locale = config.getLocale(); - - final ArtifactDescription adescr = this.artifact.getArtifactDescription(); - final DataList[] data = adescr.getOldData(); - - final double[] mm = getMinMaxKM(data); - final String river = getRiverName(data); - - int i = 0; - - // Get Data for respective gauge. - for (final Double[] range : this.gaugeRanges) { - // Gauge ranges overlap, move start and end a bit closer - // to each other. - final double rDiff = (range[1] - range[0]) / 10d; - final int fi = i; - this.wqInfoService.getWQInfo(locale, river, range[0] + rDiff, range[1] - rDiff, new AsyncCallback() { - @Override - public void onFailure(final Throwable caught) { - GWT.log("Could not recieve wq informations."); - SC.warn(caught.getMessage()); - } - - @Override - public void onSuccess(final WQInfoObject[] wqi) { - final int num = wqi != null ? wqi.length : 0; - GWT.log("Received " + num + " wq informations (" + fi + "."); - - if (num == 0) { - return; - } - - addWQInfo(wqi, fi); - } - }); - i++; - } - } - - /** Add Info to helper table for gauge at index gaugeIdx. */ - protected void addWQInfo(final WQInfoObject[] wqi, final int gaugeIdx) { - for (final WQInfoObject wi : wqi) { - final WQInfoRecord rec = new WQInfoRecord(wi); - - if (wi.getType().equals("W")) { - this.wTables.get(gaugeIdx).addData(rec); - } else { - this.qdTables.get(gaugeIdx).addData(rec); - } - } - } - - /** - * Determines the min and max kilometer value selected in a former state. A - * bit silly, but we need to run over each value of the "old data" to find - * such values because it is not available here. - * - * @param data - * The DataList which contains the whole data inserted for the - * current artifact. - * - * @return a double array with [min, max]. - */ - protected double[] getMinMaxKM(final DataList[] data) { - final ArtifactDescription adesc = this.artifact.getArtifactDescription(); - return adesc.getKMRange(); - } - - /** - * Returns the name of the selected river. - * - * @param data - * The DataList with all data. - * - * @return the name of the current river. - */ - protected String getRiverName(final DataList[] data) { - final ArtifactDescription adesc = this.artifact.getArtifactDescription(); - return adesc.getRiver(); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/bundu/BunduWstWQPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/bundu/BunduWstWQPanel.java Tue Jul 24 10:36:18 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/bundu/BunduWstWQPanel.java Tue Jul 24 10:39:03 2018 +0200 @@ -9,17 +9,40 @@ package org.dive4elements.river.client.client.ui.bundu; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.dive4elements.river.client.client.services.DynamicMainValuesService; +import org.dive4elements.river.client.client.services.DynamicMainValuesServiceAsync; +import org.dive4elements.river.client.client.ui.AbstractWQAdaptedInputPanel; import org.dive4elements.river.client.client.ui.DoubleArrayPanel; -import org.dive4elements.river.client.client.ui.WQAdaptedInputPanel; +import org.dive4elements.river.client.client.ui.wq.QDTable; import org.dive4elements.river.client.shared.model.Data; import org.dive4elements.river.client.shared.model.DataItem; import org.dive4elements.river.client.shared.model.DataList; +import org.dive4elements.river.client.shared.model.DefaultData; +import org.dive4elements.river.client.shared.model.DefaultDataItem; +import org.dive4elements.river.client.shared.model.WQDataItem; +import org.dive4elements.river.client.shared.model.WQInfoObject; +import com.google.gwt.core.client.GWT; import com.google.gwt.i18n.client.NumberFormat; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.smartgwt.client.types.TitleOrientation; +import com.smartgwt.client.types.VerticalAlignment; +import com.smartgwt.client.types.Visibility; import com.smartgwt.client.widgets.Canvas; +import com.smartgwt.client.widgets.Label; +import com.smartgwt.client.widgets.form.DynamicForm; +import com.smartgwt.client.widgets.form.fields.RadioGroupItem; +import com.smartgwt.client.widgets.form.fields.TextItem; +import com.smartgwt.client.widgets.form.fields.events.ChangeEvent; +import com.smartgwt.client.widgets.form.fields.events.ChangeHandler; +import com.smartgwt.client.widgets.form.validator.IntegerRangeValidator; +import com.smartgwt.client.widgets.layout.HLayout; +import com.smartgwt.client.widgets.layout.VLayout; +import com.smartgwt.client.widgets.tab.Tab; /** * This UIProvider creates a widget to enter W or Q data for @@ -27,33 +50,216 @@ * * @author Andre Heinecke */ -public class BunduWstWQPanel extends WQAdaptedInputPanel { - private static final long serialVersionUID = -3218827566805476423L; +public class BunduWstWQPanel extends AbstractWQAdaptedInputPanel { + + private static final long serialVersionUID = -1L; + + private static enum mode { + Q, UD + } + + /** Service to fetch W/Q MainValues. */ + private final DynamicMainValuesServiceAsync mainValueService = GWT.create(DynamicMainValuesService.class); + + private final RadioGroupItem radiogroup = new RadioGroupItem(); private int bezugsjahr = 0; + private int qSeriesLength = 0; - /** get bezugsjahr + range from server HERE **/ + private Canvas list; + + private final DynamicForm udForm = new DynamicForm(); + + private final TextItem udInputItem = new TextItem(); + @Override - public Canvas create(final DataList data) { - + protected void beforeCreate(final DataList data) { for (final Data container : data.getAll()) { - - for (final DataItem item : container.getItems()) { - if ("ignore_bezugsjahr".equals(item.getLabel())) { - this.bezugsjahr = Integer.valueOf(item.getStringValue()); - } else if ("ignore_q_series_length".equals(item.getLabel())) { - this.qSeriesLength = Integer.valueOf(item.getStringValue()); + final DataItem[] items = container.getItems(); + if (items != null) { + for (final DataItem item : items) { + if ("ignore_bezugsjahr".equals(item.getLabel())) { + this.bezugsjahr = Integer.valueOf(item.getStringValue()); + } else if ("ignore_q_series_length".equals(item.getLabel())) { + this.qSeriesLength = Integer.valueOf(item.getStringValue()); + } } } } - return super.create(data); } - // TODO: ValidateRange verstehen und dann ggf. Löschen/Ändern/was auch immer @Override - protected List validateRange(final Map ranges) { + protected void afterCreate() { + } + + @Override + protected Canvas createWidget(final DataList dataList) { + final VLayout layout = new VLayout(); + final Canvas mode = createMode(dataList); + + this.list = createList(dataList); + + this.udInputItem.setShowTitle(false); + this.udInputItem.setWidth(120); + final IntegerRangeValidator validator = new IntegerRangeValidator(); + validator.setMax(364); + validator.setMin(0); + validator.setErrorMessage(this.MSG.bundu_bezugswst_validation_range()); + this.udInputItem.setRequiredMessage(this.MSG.bundu_bezugswst_validation_range()); + this.udInputItem.setValidators(validator); + this.udInputItem.setValidateOnChange(true); + this.udForm.setFields(this.udInputItem); + + final List items = getWQItems(dataList); + final int listHeight = ROW_HEIGHT * items.size(); + + mode.setHeight(25); + mode.setWidth(200); + + layout.addMember(mode); + layout.addMember(this.list); + layout.addMember(this.udForm); + layout.setHeight(25 + listHeight); + layout.setWidth(350); + enableQ(); + return layout; + } + + /** + * Create radio button for switching + * Radiobutton-change also triggers helper panel tab selection. + */ + + private Canvas createMode(final DataList dataList) { + this.radiogroup.setShowTitle(false); + this.radiogroup.setVertical(false); + this.radiogroup.setWidth(200); + + final LinkedHashMap wqValues = new LinkedHashMap(); + wqValues.put(String.valueOf(mode.Q), this.MSG.wqQatGauge()); + wqValues.put(String.valueOf(mode.UD), this.MSG.bundu_bezugswst_mode_ud()); + this.radiogroup.setValueMap(wqValues); + this.radiogroup.setValue(String.valueOf(mode.Q)); + + this.modes = new DynamicForm(); + this.modes.setFields(this.radiogroup); + this.modes.setWidth(200); + this.radiogroup.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(final ChangeEvent e) { + + final String value = e.getValue().toString(); + if (value.equals(String.valueOf(mode.UD))) { + enableQ(); + } else if (value.equals(String.valueOf(mode.Q))) { + enableUD(); + } + } + }); + return this.modes; + } + + private void enableUD() { + BunduWstWQPanel.this.list.setVisibility(Visibility.VISIBLE); + BunduWstWQPanel.this.udForm.setVisibility(Visibility.HIDDEN); + BunduWstWQPanel.this.tabs.enable(); + } + + private void enableQ() { + BunduWstWQPanel.this.list.setVisibility(Visibility.HIDDEN); + BunduWstWQPanel.this.udForm.setVisibility(Visibility.VISIBLE); + BunduWstWQPanel.this.tabs.disable(); + } + + private final String getMode() { + return (String) this.radiogroup.getValue(); + } + + @Override + public Data[] getData() { + final Data[] data = new Data[2]; + final String modeStr = getMode(); + final DataItem item = new DefaultDataItem("bundu.wst.mode", "bundu.wst.mode", modeStr); + final Data modeData = new DefaultData("bundu.wst.mode", null, null, new DataItem[] { item }); + data[0] = modeData; + if (modeStr.equals(mode.Q.toString())) { + data[1] = getWQValues("wq_values"); + } else if (modeStr.equals(mode.UD.toString())) { + final String udValue = this.udInputItem.getValueAsString(); // in validate findet der int-check statt; er verhindert ein weitergehen, falls der Wert + // nicht int-kompatibel ist + final DataItem itemV = new DefaultDataItem("bundu.wst.ud_value", "bundu.wst.ud_value", udValue); + data[1] = new DefaultData("bundu.wst.ud_value", null, null, new DataItem[] { itemV }); + } + return data; + } + + @Override + protected void createTabs() { + for (int i = 0; i < this.gaugeRanges.size(); i++) { + final Tab qTab = new Tab(this.MSG.wq_table_q()); + final QDTable qdTable = new QDTable(); + this.qdTables.add(qdTable); + qdTable.showSelect(); + qTab.setPane(qdTable); + this.tabs.addTab(qTab, i); + } + this.tabs.setSelectedTab(0); + } + + private Canvas createList(final DataList dataList) { + final VLayout layout = new VLayout(); + + final List items = getWQItems(dataList); + + int i = 0; + for (final DataItem item : items) { + if (item instanceof WQDataItem) { + final String title = item.getLabel(); + final String label = item.getStringValue(); + + this.tabs.getTab(i).setTitle(this.tabs.getTab(i).getTitle() + " (" + label + ")"); + + final DoubleArrayPanel dap = new DoubleArrayPanel(label, null, this, null, TitleOrientation.LEFT); + this.wqranges.put(title, dap); + this.doubleArrayPanels.add(dap); + if (item instanceof WQDataItem) { + final WQDataItem wq = (WQDataItem) item; + final double[] mmQ = wq.getQRange(); + this.qranges.put(title, mmQ); + + } + layout.addMember(dap); + i++; + } + } + + layout.setHeight(items.size() * ROW_HEIGHT); + + return layout; + } + + @Override + public List validate() { final List errors = new ArrayList(); + if (getMode().equals(mode.Q.toString())) { + errors.addAll(this.validateRange(this.qranges)); + } else if (getMode().equals(mode.UD.toString())) { + try { + if (this.udInputItem.validate()) { + errors.add(this.udInputItem.getRequiredMessage()); + } + } + catch (final NumberFormatException e) { + errors.add(this.MSG.error_invalid_integer()); + } + } + return errors; + } + + private List validateRange(final Map ranges) { + final List errors = new ArrayList(); + final NumberFormat nf = NumberFormat.getDecimalFormat(); for (final DoubleArrayPanel dap : this.wqranges.values()) { @@ -90,5 +296,53 @@ } return errors; } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : + + @Override + public Canvas createOld(final DataList dataList) { + final List all = dataList.getAll(); + final Data wqData = getData(all, "wq_values"); + final Data wqMode = getData(all, "bundu.wst.mode"); + final Data udValue = getData(all, "bundu.wst.ud_value"); + + final boolean isQ = wqMode.getItems()[0].getStringValue().equals(String.valueOf(mode.Q)); + final Canvas back = getBackButton(dataList.getState()); + + final HLayout valLayout = new HLayout(); + final HLayout modeLayout = new HLayout(); + final VLayout vlayout = new VLayout(); + + final Label wqLabel = new Label(dataList.getLabel()); + final Label modeLabel = new Label(""); + + wqLabel.setValign(VerticalAlignment.TOP); + + wqLabel.setWidth(200); + wqLabel.setHeight(25); + modeLabel.setHeight(25); + modeLabel.setWidth(200); + + valLayout.addMember(wqLabel); + if (isQ) { + valLayout.addMember(createOldWQValues(wqData, true)); + } else { + valLayout.addMember(new Label(udValue.getItems()[0].getStringValue() + " [d/a]")); + } + valLayout.addMember(back); + modeLayout.addMember(modeLabel); + + vlayout.addMember(valLayout); + vlayout.addMember(modeLayout); + + return vlayout; + } + + @Override + protected void callMainValuesService(final String locale, final String river, final double start, final double end, + final AsyncCallback cb) { + + final int startYear = this.bezugsjahr - this.qSeriesLength; + final int endYear = this.bezugsjahr; + + this.mainValueService.getWQInfo(locale, river, start, end, startYear, endYear, cb); + } +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/server/AbstractMainValuesServiceImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/AbstractMainValuesServiceImpl.java Tue Jul 24 10:39:03 2018 +0200 @@ -0,0 +1,221 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * 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.client.server; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Comparator; +import java.util.List; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.dive4elements.artifacts.common.ArtifactNamespaceContext; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.artifacts.httpclient.exceptions.ConnectionException; +import org.dive4elements.artifacts.httpclient.http.HttpClient; +import org.dive4elements.artifacts.httpclient.http.HttpClientImpl; +import org.dive4elements.river.client.shared.exceptions.ServerException; +import org.dive4elements.river.client.shared.model.WQInfoObject; +import org.dive4elements.river.client.shared.model.WQInfoObjectImpl; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.google.gwt.user.server.rpc.RemoteServiceServlet; + +/** + * @author Ingo Weinzierl + */ +abstract class AbstractMainValuesServiceImpl extends RemoteServiceServlet { + + private static final Logger log = Logger.getLogger(DynamicMainValuesServiceImpl.class); + + private static final Comparator WQ_INFO_OBJECT_CMP = new Comparator() { + @Override + public int compare(final WQInfoObject a, final WQInfoObject b) { + + // Descending by type: Qs before Ds + final int cmp = a.getType().compareTo(b.getType()); + if (cmp < 0) + return +1; + if (cmp > 0) + return -1; + + // Ascending by value + final double diff = a.getValue() - b.getValue(); + if (diff < 0d) + return -1; + if (diff > 0d) + return +1; + return 0; + } + }; + + private static final String ERROR_NO_WQINFO_FOUND = "error_no_wqinfo_found"; + + private static final String XPATH_WQS = "art:service/art:mainvalues/art:mainvalue"; + + private static final long serialVersionUID = 1L; + + protected final Document createInput(final String river, final double from, final double to, final Integer startYear, final Integer endYear) { + + final Document input = XMLUtils.newDocument(); + + final XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(input, ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + final Element mainvalues = ec.create("mainvalues"); + + final Element riverEl = ec.create("river"); + riverEl.setTextContent(river); + mainvalues.appendChild(riverEl); + + final Element startEl = ec.create("start"); + startEl.setTextContent(Double.valueOf(from).toString()); + mainvalues.appendChild(startEl); + + final Element endEl = ec.create("end"); + endEl.setTextContent(Double.valueOf(to).toString()); + mainvalues.appendChild(endEl); + + if (startYear != null) { + final Element startYearElement = ec.create("startYear"); + startYearElement.setTextContent(Integer.toString(startYear)); + mainvalues.appendChild(startYearElement); + } + + if (endYear != null) { + final Element endYearElement = ec.create("endYear"); + endYearElement.setTextContent(Integer.toString(endYear)); + mainvalues.appendChild(endYearElement); + } + + input.appendChild(mainvalues); + + return input; + } + + protected final WQInfoObject[] callService(final String serviceName, final Document input, final String locale) throws ServerException { + final String url = getServletContext().getInitParameter("server-url"); + + final HttpClient client = new HttpClientImpl(url, locale); + + try { + final Document result = client.callService(url, serviceName, input); + + log.debug("Extract wq info objects now."); + final WQInfoObject[] objects = extractWQInfoObjects(result); + + if (objects.length > 0) { + return objects; + } + } + catch (final ConnectionException ce) { + log.error(ce, ce); + } + + throw new ServerException(ERROR_NO_WQINFO_FOUND); + } + + /** + * Extracts all wq info objects from result document. + * + * @param result + * The document retrieved by the server. + * + * @return a list of WQInfoObjects. + */ + private WQInfoObject[] extractWQInfoObjects(final Document result) throws ServerException { + final NodeList list = (NodeList) XMLUtils.xpath(result, XPATH_WQS, XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE); + + if (list == null || list.getLength() == 0) { + log.warn("No wq info found."); + + throw new ServerException(ERROR_NO_WQINFO_FOUND); + } + + final boolean debug = log.isDebugEnabled(); + + final int num = list.getLength(); + if (debug) { + log.debug("Response contains " + num + " objects."); + } + + final List objects = new ArrayList(num); + + for (int i = 0; i < num; i++) { + final WQInfoObject obj = buildWQInfoObject(list.item(i)); + + if (obj != null) { + objects.add(obj); + } + } + + if (debug) { + log.debug("Retrieved " + objects.size() + " wq values"); + } + + final WQInfoObject[] array = objects.toArray(new WQInfoObject[objects.size()]); + + Arrays.sort(array, WQ_INFO_OBJECT_CMP); + + return array; + } + + /** + * Extracts information for a single wq info object and intializes an + * WQInfoObject with them. + * + * @param node + * The node that contains the information. + * + * @return a valid WQInfoObject. + */ + private static WQInfoObject buildWQInfoObject(final Node node) { + + final String name = XMLUtils.xpathString(node, "@name", ArtifactNamespaceContext.INSTANCE); + + final String type = XMLUtils.xpathString(node, "@type", ArtifactNamespaceContext.INSTANCE); + + final String value = XMLUtils.xpathString(node, "@value", ArtifactNamespaceContext.INSTANCE); + + final String official = XMLUtils.xpathString(node, "@official", ArtifactNamespaceContext.INSTANCE); + + final String starttime = XMLUtils.xpathString(node, "@starttime", ArtifactNamespaceContext.INSTANCE); + + final String stoptime = XMLUtils.xpathString(node, "@stoptime", ArtifactNamespaceContext.INSTANCE); + + if (name != null && type != null) { + try { + final Calendar cal = Calendar.getInstance(); + java.util.Date start = null; + java.util.Date stop = null; + if (!starttime.equals("")) { + cal.setTimeInMillis(Long.parseLong(starttime)); + start = cal.getTime(); + } + if (!stoptime.equals("")) { + cal.setTimeInMillis(Long.parseLong(stoptime)); + stop = cal.getTime(); + } + return new WQInfoObjectImpl(name, type, new Double(value), official != null && official.equalsIgnoreCase("true"), start, stop); + } + catch (final NumberFormatException nfe) { + log.warn(nfe.getLocalizedMessage()); + } + } + + log.warn("Invalid wq info object found."); + + return null; + } +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/server/DynamicMainValuesServiceImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/DynamicMainValuesServiceImpl.java Tue Jul 24 10:39:03 2018 +0200 @@ -0,0 +1,30 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * 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.client.server; + +import org.dive4elements.river.client.client.services.DynamicMainValuesService; +import org.dive4elements.river.client.shared.exceptions.ServerException; +import org.dive4elements.river.client.shared.model.WQInfoObject; +import org.w3c.dom.Document; + +/** + * @author Ingo Weinzierl + */ +public class DynamicMainValuesServiceImpl extends AbstractMainValuesServiceImpl implements DynamicMainValuesService { + private static final long serialVersionUID = 1L; + + @Override + public WQInfoObject[] getWQInfo(final String locale, final String river, final double from, final double to, final int startYear, final int endYear) + throws ServerException { + + final Document input = createInput(river, from, to, startYear, endYear); + + return callService("dynamicMainvalues", input, locale); + } +} \ No newline at end of file diff -r 6c88ad449c83 -r 82c67b859aa7 gwt-client/src/main/java/org/dive4elements/river/client/server/WQInfoServiceImpl.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/WQInfoServiceImpl.java Tue Jul 24 10:36:18 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/WQInfoServiceImpl.java Tue Jul 24 10:39:03 2018 +0200 @@ -8,233 +8,26 @@ package org.dive4elements.river.client.server; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Comparator; -import java.util.List; - -import javax.xml.xpath.XPathConstants; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - import org.apache.log4j.Logger; - -import com.google.gwt.user.server.rpc.RemoteServiceServlet; - -import org.dive4elements.artifacts.common.ArtifactNamespaceContext; -import org.dive4elements.artifacts.common.utils.XMLUtils; - -import org.dive4elements.artifacts.httpclient.exceptions.ConnectionException; -import org.dive4elements.artifacts.httpclient.http.HttpClient; -import org.dive4elements.artifacts.httpclient.http.HttpClientImpl; - +import org.dive4elements.river.client.client.services.WQInfoService; import org.dive4elements.river.client.shared.exceptions.ServerException; -import org.dive4elements.river.client.client.services.WQInfoService; import org.dive4elements.river.client.shared.model.WQInfoObject; -import org.dive4elements.river.client.shared.model.WQInfoObjectImpl; - +import org.w3c.dom.Document; /** * @author Ingo Weinzierl */ -public class WQInfoServiceImpl -extends RemoteServiceServlet -implements WQInfoService -{ - private static final Logger log = - Logger.getLogger(WQInfoServiceImpl.class); - - public static final String ERROR_NO_WQINFO_FOUND = - "error_no_wqinfo_found"; +public class WQInfoServiceImpl extends AbstractMainValuesServiceImpl implements WQInfoService { + private static final long serialVersionUID = 1L; - public static final String XPATH_WQS = - "art:service/art:mainvalues/art:mainvalue"; - + private static final Logger log = Logger.getLogger(WQInfoServiceImpl.class); - public WQInfoObject[] getWQInfo( - String locale, - String river, - double from, - double to) - throws ServerException - { + @Override + public WQInfoObject[] getWQInfo(final String locale, final String river, final double from, final double to) throws ServerException { log.info("WQInfoServiceImpl.getWQInfo"); - String url = getServletContext().getInitParameter("server-url"); - - Document doc = XMLUtils.newDocument(); - - XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( - doc, - ArtifactNamespaceContext.NAMESPACE_URI, - ArtifactNamespaceContext.NAMESPACE_PREFIX); - - Element mainvalues = ec.create("mainvalues"); - Element riverEl = ec.create("river"); - Element startEl = ec.create("start"); - Element endEl = ec.create("end"); - - riverEl.setTextContent(river); - startEl.setTextContent(Double.valueOf(from).toString()); - endEl.setTextContent(Double.valueOf(to).toString()); - - mainvalues.appendChild(riverEl); - mainvalues.appendChild(startEl); - mainvalues.appendChild(endEl); - - doc.appendChild(mainvalues); - - HttpClient client = new HttpClientImpl(url, locale); - - try { - Document result = client.callService(url, "mainvalues", doc); - - log.debug("Extract wq info objects now."); - WQInfoObject[] objects = extractWQInfoObjects(result); - - if (objects.length > 0) { - return objects; - } - } - catch (ConnectionException ce) { - log.error(ce, ce); - } - - throw new ServerException(ERROR_NO_WQINFO_FOUND); - } - - - /** - * Extracts all wq info objects from result document. - * - * @param result The document retrieved by the server. - * - * @return a list of WQInfoObjects. - */ - protected WQInfoObject[] extractWQInfoObjects(Document result) - throws ServerException - { - NodeList list = (NodeList) XMLUtils.xpath( - result, - XPATH_WQS, - XPathConstants.NODESET, - ArtifactNamespaceContext.INSTANCE); - - if (list == null || list.getLength() == 0) { - log.warn("No wq info found."); - - throw new ServerException(ERROR_NO_WQINFO_FOUND); - } - - boolean debug = log.isDebugEnabled(); - - int num = list.getLength(); - if (debug) { - log.debug("Response contains " + num + " objects."); - } - - List objects = - new ArrayList(num); - - for (int i = 0; i < num; i++) { - WQInfoObject obj = buildWQInfoObject(list.item(i)); - - if (obj != null) { - objects.add(obj); - } - } + final Document input = createInput(river, from, to, null, null); - if (debug) { - log.debug("Retrieved " + objects.size() + " wq values"); - } - - WQInfoObject [] array = (WQInfoObject[]) - objects.toArray(new WQInfoObject[objects.size()]); - - Arrays.sort(array, WQ_INFO_OBJECT_CMP); - - return array; + return callService("mainvalues", input, locale); } - - public static final Comparator WQ_INFO_OBJECT_CMP = - new Comparator() { - @Override - public int compare(WQInfoObject a, WQInfoObject b) { - - // Descending by type: Qs before Ds - int cmp = a.getType().compareTo(b.getType()); - if (cmp < 0) return +1; - if (cmp > 0) return -1; - - // Ascending by value - double diff = a.getValue() - b.getValue(); - if (diff < 0d) return -1; - if (diff > 0d) return +1; - return 0; - } - }; - - /** - * Extracts information for a single wq info object and intializes an - * WQInfoObject with them. - * - * @param node The node that contains the information. - * - * @return a valid WQInfoObject. - */ - protected static WQInfoObject buildWQInfoObject(Node node) { - - String name = XMLUtils.xpathString( - node, "@name", ArtifactNamespaceContext.INSTANCE); - - String type = XMLUtils.xpathString( - node, "@type", ArtifactNamespaceContext.INSTANCE); - - String value = XMLUtils.xpathString( - node, "@value", ArtifactNamespaceContext.INSTANCE); - - String official = XMLUtils.xpathString( - node, "@official", ArtifactNamespaceContext.INSTANCE); - - String starttime = XMLUtils.xpathString( - node, "@starttime", ArtifactNamespaceContext.INSTANCE); - - String stoptime = XMLUtils.xpathString( - node, "@stoptime", ArtifactNamespaceContext.INSTANCE); - - if (name != null && type != null) { - try { - Calendar cal = Calendar.getInstance(); - java.util.Date start = null; - java.util.Date stop = null; - if (!starttime.equals("")) { - cal.setTimeInMillis(Long.parseLong(starttime)); - start = cal.getTime(); - } - if (!stoptime.equals("")) { - cal.setTimeInMillis(Long.parseLong(stoptime)); - stop = cal.getTime(); - } - return new WQInfoObjectImpl( - name, - type, - new Double(value), - official != null && official.equalsIgnoreCase("true"), - start, - stop); - } - catch (NumberFormatException nfe) { - log.warn(nfe.getLocalizedMessage()); - } - } - - log.warn("Invalid wq info object found."); - - return null; - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file