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@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: */ ingo@1631: public class MainValuesService extends FLYSService { 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: 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: 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: 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); sascha@3728: 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: { ingo@331: logger.debug("MainValuesService.getRiver"); 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); ingo@331: appendMainValues(doc, rootEl, mainValues, 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: ingo@331: protected void appendMainValues( ingo@331: Document doc, ingo@331: Element root, ingo@331: List mainValues, 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) { ingo@331: Element newEl = buildMainValueElement(doc, mainValue, 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, 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()); ingo@331: ingo@331: return el; ingo@331: } ingo@331: } ingo@331: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :