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: }