ingo@331: package de.intevation.flys.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:
ingo@331: import de.intevation.artifacts.CallMeta;
sascha@966: import de.intevation.artifacts.GlobalContext;
ingo@331:
ingo@331: import de.intevation.artifacts.common.ArtifactNamespaceContext;
ingo@331: import de.intevation.artifacts.common.utils.XMLUtils;
ingo@331: import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;
ingo@331:
ingo@331: import de.intevation.flys.model.Gauge;
ingo@331: import de.intevation.flys.model.MainValue;
ingo@331: import de.intevation.flys.model.MainValueType;
ingo@331: import de.intevation.flys.model.NamedMainValue;
ingo@331: import de.intevation.flys.model.Range;
ingo@331: import de.intevation.flys.model.River;
ingo@331:
ingo@331: import de.intevation.flys.artifacts.model.MainValuesFactory;
ingo@331: import de.intevation.flys.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:
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:
ingo@331: try {
ingo@331: River river = getRequestedRiver(data);
ingo@331: double[] minmax = getRequestedStartEnd(data, river);
ingo@331: Gauge gauge = river.determineGauge(minmax[0], minmax[1]);
ingo@331:
ingo@1659: logger.debug("Found gauge: " + gauge.getName());
ingo@1659:
ingo@331: List mainValues = getMainValues(river, gauge);
ingo@331:
ingo@331: return buildDocument(river, gauge, mainValues, context);
ingo@331: }
ingo@331: catch (NullPointerException npe) {
ingo@331: logger.error("Could not process the request.");
ingo@331: logger.error(npe, npe);
ingo@331:
ingo@331: return XMLUtils.newDocument();
ingo@331: }
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:
ingo@331: if (riverStr == null || riverStr.trim().length() == 0) {
ingo@331: throw new NullPointerException("No river found in the request.");
ingo@331: }
ingo@331:
ingo@331: River river = RiverFactory.getRiver(riverStr);
ingo@331:
ingo@331: if (river == null) {
ingo@331: throw new NullPointerException("No such river found: " + riverStr);
ingo@331: }
ingo@331:
ingo@331: return river;
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:
ingo@331: try {
ingo@331: double start = Double.parseDouble(startStr);
ingo@331: double end = Double.parseDouble(endStr);
ingo@331:
ingo@331: logger.debug("Found start: " + start);
ingo@331: logger.debug("Found end: " + end);
ingo@331:
ingo@331: return new double[] { start, end };
ingo@331: }
ingo@331: catch (NumberFormatException nfe) {
ingo@331: logger.warn(nfe, nfe);
ingo@331:
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: */
ingo@331: protected List getMainValues(River river, Gauge gauge)
ingo@331: throws NullPointerException
ingo@331: {
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:
ingo@1631: List mainValues = MainValuesFactory.getMainValues(gauge);
ingo@331:
ingo@1631: if (mainValues == null || mainValues.isEmpty()) {
ingo@1631: throw new NullPointerException("No main values found.");
ingo@331: }
ingo@1631:
ingo@1631: logger.debug(mainValues.size() + " main values found.");
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 :