teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5994: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5994: * documentation coming with Dive4Elements River for details. teichmann@5863: */ teichmann@5863: teichmann@5831: package org.dive4elements.river.artifacts.services; ingo@331: ingo@331: import java.util.List; ingo@331: ingo@331: import org.apache.log4j.Logger; ingo@331: ingo@331: import org.w3c.dom.Document; ingo@331: import org.w3c.dom.Element; ingo@331: teichmann@5831: import org.dive4elements.artifacts.CallMeta; teichmann@5831: import org.dive4elements.artifacts.GlobalContext; ingo@331: teichmann@5831: import org.dive4elements.artifacts.common.ArtifactNamespaceContext; teichmann@5831: import org.dive4elements.artifacts.common.utils.XMLUtils; teichmann@5831: import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; ingo@331: teichmann@5831: import org.dive4elements.river.model.Gauge; teichmann@5831: import org.dive4elements.river.model.MainValue; teichmann@5831: import org.dive4elements.river.model.MainValueType; teichmann@5831: import org.dive4elements.river.model.NamedMainValue; teichmann@6356: import org.dive4elements.river.model.OfficialLine; teichmann@5831: import org.dive4elements.river.model.Range; teichmann@5831: import org.dive4elements.river.model.River; teichmann@5831: teichmann@5831: import org.dive4elements.river.artifacts.model.RiverFactory; ingo@331: ingo@331: ingo@331: /** ingo@331: * This service returns the main values of a river's gauge based on the start ingo@331: * and end point of the river. ingo@331: * ingo@331: * @author Ingo Weinzierl ingo@331: */ teichmann@5868: public class MainValuesService extends D4EService { ingo@331: ingo@331: /** The logger that is used by this service.*/ ingo@331: private static Logger logger = Logger.getLogger(MainValuesService.class); ingo@331: ingo@331: /** The XPath that points to the river definition of the incoming request.*/ ingo@331: public static final String XPATH_RIVER = "/art:mainvalues/art:river/text()"; ingo@331: ingo@331: /** The XPath that points to the start definition of the incoming request.*/ ingo@444: public static final String XPATH_START = "/art:mainvalues/art:start/text()"; ingo@331: ingo@331: /** The XPath that points to the end definition of the incoming request.*/ ingo@444: public static final String XPATH_END = "/art:mainvalues/art:end/text()"; ingo@331: felix@7555: protected CallMeta callMeta; felix@7555: felix@7555: ingo@331: /** ingo@331: * The default constructor. ingo@331: */ ingo@331: public MainValuesService() { ingo@331: } ingo@331: sascha@3728: private static final Document error(String msg) { sascha@3728: logger.debug(msg); sascha@3728: return XMLUtils.newDocument(); sascha@3728: } sascha@3728: ingo@331: sascha@966: @Override ingo@1631: public Document doProcess( sascha@966: Document data, sascha@966: GlobalContext context, sascha@966: CallMeta callMeta sascha@966: ) { ingo@331: logger.debug("MainValuesService.process"); ingo@331: felix@7555: this.callMeta = callMeta; felix@7555: sascha@3728: River river = getRequestedRiver(data); sascha@3728: if (river == null) { sascha@3728: return error("no river found."); sascha@3728: } ingo@1659: sascha@3728: double[] minmax = getRequestedStartEnd(data, river); aheinecke@6107: Gauge gauge = river.determineGauge(minmax[0], minmax[1]); ingo@331: sascha@3728: if (gauge == null) { sascha@3728: return error("no gauge found."); ingo@331: } ingo@331: sascha@3728: List mainValues = getMainValues(river, gauge); sascha@3728: sascha@3728: return buildDocument(river, gauge, mainValues, context); ingo@331: } ingo@331: ingo@331: ingo@331: /** ingo@331: * This method extracts the river from the incoming request. If no river ingo@331: * string was found or no river is found in the database based on this ingo@331: * string a NullPointerException is thrown. ingo@331: * ingo@331: * @param data The incoming request data. ingo@331: * ingo@331: * @return the River object. ingo@331: */ ingo@331: protected River getRequestedRiver(Document data) ingo@331: throws NullPointerException ingo@331: { felix@7552: logger.debug("MainValuesService.getRequestedRiver"); ingo@331: ingo@331: String riverStr = XMLUtils.xpathString( ingo@331: data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE); ingo@331: sascha@3728: return riverStr != null && (riverStr = riverStr.trim()).length() > 0 sascha@3728: ? RiverFactory.getRiver(riverStr) sascha@3728: : null; ingo@331: } ingo@331: ingo@331: ingo@331: /** ingo@331: * This method extracts the start and end point from incoming request ingo@331: * document and returns both values in an array. If no start and end strings ingo@331: * are found in the document, the min/max values of the river are ingo@331: * returned. ingo@331: * ingo@331: * @param data The incoming request data. ingo@331: * @param river The river of the request. ingo@331: * ingo@331: * @return the start and end point. ingo@331: */ ingo@331: protected double[] getRequestedStartEnd(Document data, River river) { ingo@331: logger.debug("MainValuesService.getStartEnd"); ingo@331: ingo@331: String startStr = XMLUtils.xpathString( ingo@331: data, XPATH_START, ArtifactNamespaceContext.INSTANCE); ingo@331: ingo@331: String endStr = XMLUtils.xpathString( ingo@331: data, XPATH_END, ArtifactNamespaceContext.INSTANCE); ingo@331: sascha@3728: if (startStr == null || endStr == null) { sascha@3728: return river.determineMinMaxDistance(); sascha@3728: } sascha@3728: ingo@331: try { ingo@331: double start = Double.parseDouble(startStr); ingo@331: double end = Double.parseDouble(endStr); ingo@331: sascha@3728: if (logger.isDebugEnabled()) { sascha@3728: logger.debug("Found start: " + start); sascha@3728: logger.debug("Found end: " + end); sascha@3728: } ingo@331: ingo@331: return new double[] { start, end }; ingo@331: } ingo@331: catch (NumberFormatException nfe) { ingo@331: logger.warn(nfe, nfe); ingo@331: return river.determineMinMaxDistance(); ingo@331: } ingo@331: } ingo@331: ingo@331: ingo@331: /** ingo@331: * This method creates the result document that includes the main values of ingo@331: * the specified gauge. ingo@331: * ingo@331: * @param river The river. ingo@331: * @param gauge The gauge. ingo@331: * ingo@331: * @return a document that includes the main values of the specified river ingo@331: * at the specified gauge. ingo@331: */ sascha@3728: protected List getMainValues(River river, Gauge gauge) { sascha@3728: ingo@331: if (logger.isDebugEnabled()) { ingo@331: logger.debug("MainValuesService.buildMainValues"); ingo@331: logger.debug("River: " + river.getName()); ingo@331: logger.debug("Gauge: " + gauge.getName()); ingo@331: } ingo@331: christian@3734: List mainValues = gauge.getMainValues(); ingo@331: sascha@3728: if (logger.isDebugEnabled()) { sascha@3728: logger.debug(mainValues.size() + " main values found."); ingo@331: } ingo@1631: ingo@1631: return mainValues; ingo@331: } ingo@331: ingo@331: ingo@331: protected Document buildDocument( ingo@331: River river, ingo@331: Gauge gauge, ingo@331: List mainValues, ingo@331: Object context) ingo@331: { ingo@331: logger.debug("MainValuesService.buildDocument"); ingo@331: ingo@331: Document doc = XMLUtils.newDocument(); ingo@331: ingo@331: ElementCreator cr = new ElementCreator( ingo@331: doc, ingo@331: ArtifactNamespaceContext.NAMESPACE_URI, ingo@331: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@331: ingo@331: Element rootEl = cr.create("service"); ingo@331: cr.addAttr(rootEl, "name", "mainvalues"); ingo@331: ingo@331: doc.appendChild(rootEl); ingo@331: ingo@331: appendMetaInformation(doc, rootEl, river, gauge, context); teichmann@6482: appendMainValues(doc, rootEl, mainValues, river.getId(), context); ingo@331: ingo@331: return doc; ingo@331: } ingo@331: ingo@331: ingo@331: /** ingo@331: * This method appends some meta information to the result document. ingo@331: * Currently, the river's and gauge's names and the gauge's range are ingo@331: * appended. ingo@331: * ingo@331: * @param root The root element of the result document. ingo@331: * @param river The river. ingo@331: * @param gauge The gauge. ingo@331: * @param context The context object. ingo@331: */ ingo@331: protected void appendMetaInformation( ingo@331: Document doc, ingo@331: Element root, ingo@331: River river, ingo@331: Gauge gauge, ingo@331: Object context) ingo@331: { ingo@331: logger.debug("MainValuesService.appendMetaInformation"); ingo@331: ingo@331: ElementCreator cr = new ElementCreator( ingo@331: doc, ingo@331: ArtifactNamespaceContext.NAMESPACE_URI, ingo@331: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@331: ingo@331: Range range = gauge.getRange(); ingo@331: ingo@331: Element riverEl = cr.create("river"); ingo@331: cr.addAttr(riverEl, "name", river.getName()); ingo@331: ingo@331: Element gaugeEl = cr.create("gauge"); ingo@331: cr.addAttr(gaugeEl, "name", gauge.getName()); ingo@331: cr.addAttr(gaugeEl, "from", range.getA().toString()); ingo@331: cr.addAttr(gaugeEl, "to", range.getB().toString()); ingo@331: ingo@331: root.appendChild(riverEl); ingo@331: root.appendChild(gaugeEl); ingo@331: } ingo@331: ingo@331: teichmann@6356: /** Checks i a main value has an official associated, */ teichmann@6482: protected static boolean hasOfficialLine(NamedMainValue nmv, Integer riverId) { teichmann@6356: for (OfficialLine ol: nmv.getOfficialLines()) { teichmann@6482: if (ol.getWstColumn().getWst().getRiver().getId().equals(riverId)) { teichmann@6356: return true; teichmann@6356: } teichmann@6356: } teichmann@6356: return false; teichmann@6356: } teichmann@6356: teichmann@6356: felix@7552: /** Append xml representation of main values to document. */ ingo@331: protected void appendMainValues( ingo@331: Document doc, ingo@331: Element root, ingo@331: List mainValues, teichmann@6482: Integer riverId, ingo@331: Object context) ingo@331: { ingo@331: logger.debug("MainValuesService.appendMainValues"); ingo@331: ingo@331: ElementCreator cr = new ElementCreator( ingo@331: doc, ingo@331: ArtifactNamespaceContext.NAMESPACE_URI, ingo@331: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@331: ingo@331: Element list = cr.create("mainvalues"); ingo@331: ingo@331: for (MainValue mainValue: mainValues) { teichmann@6482: Element newEl = buildMainValueElement(doc, mainValue, riverId, context); ingo@331: ingo@331: if (newEl != null) { ingo@331: list.appendChild(newEl); ingo@331: } ingo@331: } ingo@331: ingo@331: root.appendChild(list); ingo@331: } ingo@331: ingo@331: ingo@331: /** ingo@331: * This method builds a concrete mainvalue element. This element consists of ingo@331: * three attributes: the value, its name and its type. ingo@331: * ingo@331: * @param doc The owner document. ingo@331: * @param mainValue The mainvalue. ingo@331: * @param context The context object. ingo@331: * ingo@331: * @return a mainvalue element. ingo@331: */ ingo@331: protected Element buildMainValueElement( ingo@331: Document doc, ingo@331: MainValue mainValue, teichmann@6482: Integer riverId, ingo@331: Object context) ingo@331: { ingo@331: ElementCreator cr = new ElementCreator( ingo@331: doc, ingo@331: ArtifactNamespaceContext.NAMESPACE_URI, ingo@331: ArtifactNamespaceContext.NAMESPACE_PREFIX); ingo@331: ingo@331: NamedMainValue namedMainValue = mainValue.getMainValue(); ingo@331: MainValueType mainValueType = namedMainValue.getType(); ingo@331: ingo@331: Element el = cr.create("mainvalue"); ingo@331: ingo@331: cr.addAttr(el, "value", mainValue.getValue().toString()); ingo@331: cr.addAttr(el, "name", namedMainValue.getName()); ingo@331: cr.addAttr(el, "type", mainValueType.getName()); felix@7553: if (mainValue.getTimeInterval() != null) { felix@7553: if (mainValue.getTimeInterval().getStartTime() != null) { felix@7555: cr.addAttr(el, "starttime", felix@7561: Long.toString(mainValue.getTimeInterval().getStartTime().getTime())); felix@7553: } felix@7553: if (mainValue.getTimeInterval().getStopTime() != null) { felix@7555: cr.addAttr(el, "stoptime", felix@7561: Long.toString(mainValue.getTimeInterval().getStopTime().getTime())); felix@7553: } felix@7553: } ingo@331: teichmann@6482: if (hasOfficialLine(namedMainValue, riverId)) { teichmann@6356: cr.addAttr(el, "official", "true"); teichmann@6356: } teichmann@6356: ingo@331: return el; ingo@331: } ingo@331: } ingo@331: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :