gernotbelger@9288: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
gernotbelger@9288: * Software engineering by Intevation GmbH
gernotbelger@9288: *
gernotbelger@9288: * This file is Free Software under the GNU AGPL (>=v3)
gernotbelger@9288: * and comes with ABSOLUTELY NO WARRANTY! Check out the
gernotbelger@9288: * documentation coming with Dive4Elements River for details.
gernotbelger@9288: */
gernotbelger@9288:
gernotbelger@9288: package org.dive4elements.river.artifacts.services;
gernotbelger@9288:
gernotbelger@9288: import static org.dive4elements.river.backend.utils.EpsilonComparator.CMP;
gernotbelger@9288:
gernotbelger@9288: import java.util.List;
gernotbelger@9288:
gernotbelger@9288: import org.apache.log4j.Logger;
gernotbelger@9288: import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
gernotbelger@9288: import org.dive4elements.artifacts.common.utils.XMLUtils;
gernotbelger@9288: import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
gernotbelger@9288: import org.dive4elements.river.artifacts.model.RiverFactory;
gernotbelger@9288: import org.dive4elements.river.model.Gauge;
gernotbelger@9288: import org.dive4elements.river.model.MainValue;
gernotbelger@9288: import org.dive4elements.river.model.MainValueType;
gernotbelger@9288: import org.dive4elements.river.model.NamedMainValue;
gernotbelger@9288: import org.dive4elements.river.model.OfficialLine;
gernotbelger@9288: import org.dive4elements.river.model.Range;
gernotbelger@9288: import org.dive4elements.river.model.River;
gernotbelger@9288: import org.w3c.dom.Document;
gernotbelger@9288: import org.w3c.dom.Element;
gernotbelger@9288:
gernotbelger@9288: /**
gernotbelger@9288: * @author Ingo Weinzierl
gernotbelger@9288: */
gernotbelger@9288: abstract class AbstractMainValuesService extends D4EService {
gernotbelger@9288:
gernotbelger@9288: private static final long serialVersionUID = 1L;
gernotbelger@9288:
gernotbelger@9288: public static final class MainValuesServiceException extends Exception {
gernotbelger@9288:
gernotbelger@9288: private static final long serialVersionUID = 1L;
gernotbelger@9288:
gernotbelger@9288: public MainValuesServiceException(final String message) {
gernotbelger@9288: super(message);
gernotbelger@9288: }
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: /** The log that is used by this service. */
gernotbelger@9288: private static Logger log = Logger.getLogger(AbstractMainValuesService.class);
gernotbelger@9288:
gernotbelger@9288: /** XPath that points to the river definition of the incoming request. */
gernotbelger@9288:
gernotbelger@9288: /** XPath that points to the start definition of the incoming request. */
gernotbelger@9288: private static final String XPATH_START = "/art:mainvalues/art:start/text()";
gernotbelger@9288:
gernotbelger@9288: /** The XPath that points to the end definition of the incoming request. */
gernotbelger@9288: private static final String XPATH_END = "/art:mainvalues/art:end/text()";
gernotbelger@9288:
gernotbelger@9288: protected static final Document error(final String msg) {
gernotbelger@9288: log.debug(msg);
gernotbelger@9288: return XMLUtils.newDocument();
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: /**
gernotbelger@9288: * This method extracts the river from the incoming request. If no river
gernotbelger@9288: * string was found or no river is found in the database based on this
gernotbelger@9288: * string a NullPointerException is thrown.
gernotbelger@9288: *
gernotbelger@9288: * @param data
gernotbelger@9288: * The incoming request data.
gernotbelger@9288: *
gernotbelger@9288: * @return the River object.
gernotbelger@9288: */
gernotbelger@9404: protected static final River getRequestedRiver(final Document data, final String XPATH_RIVER) throws MainValuesServiceException {
gernotbelger@9288: log.debug("MainValuesService.getRequestedRiver");
gernotbelger@9288:
gernotbelger@9288: String riverStr = XMLUtils.xpathString(data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE);
gernotbelger@9288:
gernotbelger@9288: if (riverStr != null && (riverStr = riverStr.trim()).length() > 0)
gernotbelger@9288: return RiverFactory.getRiver(riverStr);
gernotbelger@9288:
gernotbelger@9288: throw new MainValuesServiceException("no river found.");
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9404: protected static final Gauge getRequestedGauge(final Document data, final River river) throws MainValuesServiceException {
gernotbelger@9288:
gernotbelger@9288: final double[] minmax = getRequestedStartEnd(data, river);
gernotbelger@9288: final Gauge gauge = river.determineRefGauge(minmax, CMP.compare(minmax[0], minmax[1]) != 0);
gernotbelger@9288: if (gauge == null)
gernotbelger@9288: throw new MainValuesServiceException("no gauge found.");
gernotbelger@9288:
gernotbelger@9288: return gauge;
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: /**
gernotbelger@9288: * This method extracts the start and end point from incoming request
gernotbelger@9288: * document and returns both values in an array.
gernotbelger@9288: * If no start and end strings
gernotbelger@9288: * are found in the document, the min/max values of the river are
gernotbelger@9288: * returned.
gernotbelger@9288: *
gernotbelger@9288: * @param data
gernotbelger@9288: * The incoming request data.
gernotbelger@9288: * @param river
gernotbelger@9288: * The river of the request.
gernotbelger@9288: *
gernotbelger@9288: * @return the start and end point.
gernotbelger@9288: */
gernotbelger@9404: public static double[] getRequestedStartEnd(final Document data, final River river) {
gernotbelger@9288: log.debug("MainValuesService.getStartEnd");
gernotbelger@9288:
gernotbelger@9288: final String startStr = XMLUtils.xpathString(data, XPATH_START, ArtifactNamespaceContext.INSTANCE);
gernotbelger@9288:
gernotbelger@9288: final String endStr = XMLUtils.xpathString(data, XPATH_END, ArtifactNamespaceContext.INSTANCE);
gernotbelger@9288:
gernotbelger@9288: if (startStr == null || endStr == null) {
gernotbelger@9288: return river.determineMinMaxDistance();
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: try {
gernotbelger@9288: final double start = Double.parseDouble(startStr);
gernotbelger@9288: final double end = Double.parseDouble(endStr);
gernotbelger@9288:
gernotbelger@9288: if (log.isDebugEnabled()) {
gernotbelger@9288: log.debug("Found start: " + start);
gernotbelger@9288: log.debug("Found end: " + end);
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: return new double[] { start, end };
gernotbelger@9288: }
gernotbelger@9288: catch (final NumberFormatException nfe) {
gernotbelger@9288: log.warn(nfe, nfe);
gernotbelger@9288: return river.determineMinMaxDistance();
gernotbelger@9288: }
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: protected final Document buildDocument(final River river, final Gauge gauge, final List mainValues, final Object context) {
gernotbelger@9288: log.debug("MainValuesService.buildDocument");
gernotbelger@9288:
gernotbelger@9288: final Document doc = XMLUtils.newDocument();
gernotbelger@9288:
gernotbelger@9288: final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX);
gernotbelger@9288:
gernotbelger@9288: final Element rootEl = cr.create("service");
gernotbelger@9288: cr.addAttr(rootEl, "name", "mainvalues");
gernotbelger@9288:
gernotbelger@9288: doc.appendChild(rootEl);
gernotbelger@9288:
gernotbelger@9288: appendMetaInformation(doc, rootEl, river, gauge, context);
gernotbelger@9288: appendMainValues(doc, rootEl, mainValues, river.getId(), context);
gernotbelger@9288:
gernotbelger@9288: return doc;
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: /**
gernotbelger@9288: * This method appends some meta information to the result document.
gernotbelger@9288: * Currently, the river's and gauge's names and the gauge's range are
gernotbelger@9288: * appended.
gernotbelger@9288: *
gernotbelger@9288: * @param root
gernotbelger@9288: * The root element of the result document.
gernotbelger@9288: * @param river
gernotbelger@9288: * The river.
gernotbelger@9288: * @param gauge
gernotbelger@9288: * The gauge.
gernotbelger@9288: * @param context
gernotbelger@9288: * The context object.
gernotbelger@9288: */
gernotbelger@9404: static void appendMetaInformation(final Document doc, final Element root, final River river, final Gauge gauge, final Object context) {
gernotbelger@9288: log.debug("MainValuesService.appendMetaInformation");
gernotbelger@9288:
gernotbelger@9288: final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX);
gernotbelger@9288:
gernotbelger@9288: final Range range = gauge.getRange();
gernotbelger@9288:
gernotbelger@9288: final Element riverEl = cr.create("river");
gernotbelger@9288: cr.addAttr(riverEl, "name", river.getName());
gernotbelger@9288:
gernotbelger@9288: final Element gaugeEl = cr.create("gauge");
gernotbelger@9288: cr.addAttr(gaugeEl, "name", gauge.getName());
gernotbelger@9288: cr.addAttr(gaugeEl, "from", range.getA().toString());
gernotbelger@9288: cr.addAttr(gaugeEl, "to", range.getB().toString());
gernotbelger@9288:
gernotbelger@9288: root.appendChild(riverEl);
gernotbelger@9288: root.appendChild(gaugeEl);
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: /** Checks i a main value has an official associated, */
gernotbelger@9288: private static boolean hasOfficialLine(final NamedMainValue nmv, final Integer riverId) {
gernotbelger@9288: for (final OfficialLine ol : nmv.getOfficialLines()) {
gernotbelger@9288: if (ol.getWstColumn().getWst().getRiver().getId().equals(riverId)) {
gernotbelger@9288: return true;
gernotbelger@9288: }
gernotbelger@9288: }
gernotbelger@9288: return false;
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: /** Append xml representation of main values to document. */
gernotbelger@9288: private void appendMainValues(final Document doc, final Element root, final List mainValues, final Integer riverId, final Object context) {
gernotbelger@9288: log.debug("MainValuesService.appendMainValues");
gernotbelger@9288:
gernotbelger@9288: final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX);
gernotbelger@9288:
gernotbelger@9288: final Element list = cr.create("mainvalues");
gernotbelger@9288:
gernotbelger@9288: for (final MainValue mainValue : mainValues) {
gernotbelger@9288: final Element newEl = buildMainValueElement(doc, mainValue, riverId, context);
gernotbelger@9288:
gernotbelger@9288: if (newEl != null) {
gernotbelger@9288: list.appendChild(newEl);
gernotbelger@9288: }
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: root.appendChild(list);
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: /**
gernotbelger@9288: * This method builds a concrete mainvalue element. This element consists of
gernotbelger@9288: * three attributes: the value, its name and its type.
gernotbelger@9288: *
gernotbelger@9288: * @param doc
gernotbelger@9288: * The owner document.
gernotbelger@9288: * @param mainValue
gernotbelger@9288: * The mainvalue.
gernotbelger@9288: * @param context
gernotbelger@9288: * The context object.
gernotbelger@9288: *
gernotbelger@9288: * @return a mainvalue element.
gernotbelger@9288: */
gernotbelger@9288: private Element buildMainValueElement(final Document doc, final MainValue mainValue, final Integer riverId, final Object context) {
gernotbelger@9288: final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX);
gernotbelger@9288:
gernotbelger@9288: final NamedMainValue namedMainValue = mainValue.getMainValue();
gernotbelger@9288: final MainValueType mainValueType = namedMainValue.getType();
gernotbelger@9288:
gernotbelger@9288: final Element el = cr.create("mainvalue");
gernotbelger@9288:
gernotbelger@9288: cr.addAttr(el, "value", mainValue.getValue().toString());
gernotbelger@9288: cr.addAttr(el, "name", namedMainValue.getName());
gernotbelger@9288: cr.addAttr(el, "type", mainValueType.getName());
gernotbelger@9288: if (mainValue.getTimeInterval() != null) {
gernotbelger@9288: if (mainValue.getTimeInterval().getStartTime() != null) {
gernotbelger@9288: cr.addAttr(el, "starttime", Long.toString(mainValue.getTimeInterval().getStartTime().getTime()));
gernotbelger@9288: }
gernotbelger@9288: if (mainValue.getTimeInterval().getStopTime() != null) {
gernotbelger@9288: cr.addAttr(el, "stoptime", Long.toString(mainValue.getTimeInterval().getStopTime().getTime()));
gernotbelger@9288: }
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: if (hasOfficialLine(namedMainValue, riverId)) {
gernotbelger@9288: cr.addAttr(el, "official", "true");
gernotbelger@9288: }
gernotbelger@9288:
gernotbelger@9288: return el;
gernotbelger@9288: }
gernotbelger@9288: }