view flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/MainValuesService.java @ 1713:6d9184c745dd

Bugfix: #226 Set the upper bound of duration curve charts to 364. flys-artifacts/trunk@2985 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Mon, 17 Oct 2011 11:04:53 +0000
parents ad54896ec369
children d03e65378b9f
line wrap: on
line source
package de.intevation.flys.artifacts.services;

import java.util.List;

import org.apache.log4j.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import de.intevation.artifacts.CallMeta;
import de.intevation.artifacts.GlobalContext;

import de.intevation.artifacts.common.ArtifactNamespaceContext;
import de.intevation.artifacts.common.utils.XMLUtils;
import de.intevation.artifacts.common.utils.XMLUtils.ElementCreator;

import de.intevation.flys.model.Gauge;
import de.intevation.flys.model.MainValue;
import de.intevation.flys.model.MainValueType;
import de.intevation.flys.model.NamedMainValue;
import de.intevation.flys.model.Range;
import de.intevation.flys.model.River;

import de.intevation.flys.artifacts.model.MainValuesFactory;
import de.intevation.flys.artifacts.model.RiverFactory;


/**
 * This service returns the main values of a river's gauge based on the start
 * and end point of the river.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class MainValuesService extends FLYSService {

    /** The logger that is used by this service.*/
    private static Logger logger = Logger.getLogger(MainValuesService.class);


    /** The XPath that points to the river definition of the incoming request.*/
    public static final String XPATH_RIVER = "/art:mainvalues/art:river/text()";

    /** The XPath that points to the start definition of the incoming request.*/
    public static final String XPATH_START = "/art:mainvalues/art:start/text()";

    /** The XPath that points to the end definition of the incoming request.*/
    public static final String XPATH_END = "/art:mainvalues/art:end/text()";

    /**
     * The default constructor.
     */
    public MainValuesService() {
    }


    @Override
    public Document doProcess(
        Document      data,
        GlobalContext context,
        CallMeta      callMeta
    ) {
        logger.debug("MainValuesService.process");

        try {
            River river     = getRequestedRiver(data);
            double[] minmax = getRequestedStartEnd(data, river);
            Gauge gauge     = river.determineGauge(minmax[0], minmax[1]);

            logger.debug("Found gauge: " + gauge.getName());

            List<MainValue> mainValues = getMainValues(river, gauge);

            return buildDocument(river, gauge, mainValues, context);
        }
        catch (NullPointerException npe) {
            logger.error("Could not process the request.");
            logger.error(npe, npe);

            return XMLUtils.newDocument();
        }
    }


    /**
     * This method extracts the river from the incoming request. If no river
     * string was found or no river is found in the database based on this
     * string a NullPointerException is thrown.
     *
     * @param data The incoming request data.
     *
     * @return the River object.
     */
    protected River getRequestedRiver(Document data)
    throws    NullPointerException
    {
        logger.debug("MainValuesService.getRiver");

        String riverStr = XMLUtils.xpathString(
            data, XPATH_RIVER, ArtifactNamespaceContext.INSTANCE);

        if (riverStr == null || riverStr.trim().length() == 0) {
            throw new NullPointerException("No river found in the request.");
        }

        River river = RiverFactory.getRiver(riverStr);

        if (river == null) {
            throw new NullPointerException("No such river found: " + riverStr);
        }

        return river;
    }


    /**
     * This method extracts the start and end point from incoming request
     * document and returns both values in an array. If no start and end strings
     * are found in the document, the min/max values of the <i>river</i> are
     * returned.
     *
     * @param data The incoming request data.
     * @param river The river of the request.
     *
     * @return the start and end point.
     */
    protected double[] getRequestedStartEnd(Document data, River river) {
        logger.debug("MainValuesService.getStartEnd");

        String startStr = XMLUtils.xpathString(
            data, XPATH_START, ArtifactNamespaceContext.INSTANCE);

        String endStr = XMLUtils.xpathString(
            data, XPATH_END, ArtifactNamespaceContext.INSTANCE);

        try {
            double start = Double.parseDouble(startStr);
            double end   = Double.parseDouble(endStr);

            logger.debug("Found start: " + start);
            logger.debug("Found end: " + end);

            return new double[] { start, end };
        }
        catch (NumberFormatException nfe) {
            logger.warn(nfe, nfe);

            return river.determineMinMaxDistance();
        }
    }


    /**
     * This method creates the result document that includes the main values of
     * the specified <i>gauge</i>.
     *
     * @param river The river.
     * @param gauge The gauge.
     *
     * @return a document that includes the main values of the specified river
     * at the specified gauge.
     */
    protected List<MainValue> getMainValues(River river, Gauge gauge)
    throws    NullPointerException
    {
        if (logger.isDebugEnabled()) {
            logger.debug("MainValuesService.buildMainValues");
            logger.debug("River: " + river.getName());
            logger.debug("Gauge: " + gauge.getName());
        }

        List<MainValue> mainValues = MainValuesFactory.getMainValues(gauge);

        if (mainValues == null || mainValues.isEmpty()) {
            throw new NullPointerException("No main values found.");
        }

        logger.debug(mainValues.size() + " main values found.");

        return mainValues;
    }


    protected Document buildDocument(
        River           river,
        Gauge           gauge,
        List<MainValue> mainValues,
        Object          context)
    {
        logger.debug("MainValuesService.buildDocument");

        Document doc = XMLUtils.newDocument();

        ElementCreator cr = new ElementCreator(
            doc,
            ArtifactNamespaceContext.NAMESPACE_URI,
            ArtifactNamespaceContext.NAMESPACE_PREFIX);

        Element rootEl = cr.create("service");
        cr.addAttr(rootEl, "name", "mainvalues");

        doc.appendChild(rootEl);

        appendMetaInformation(doc, rootEl, river, gauge, context);
        appendMainValues(doc, rootEl, mainValues, context);

        return doc;
    }


    /**
     * This method appends some meta information to the result document.
     * Currently, the river's and gauge's names and the gauge's range are
     * appended.
     *
     * @param root The root element of the result document.
     * @param river The river.
     * @param gauge The gauge.
     * @param context The context object.
     */
    protected void appendMetaInformation(
        Document doc,
        Element  root,
        River    river,
        Gauge    gauge,
        Object   context)
    {
        logger.debug("MainValuesService.appendMetaInformation");

        ElementCreator cr = new ElementCreator(
            doc,
            ArtifactNamespaceContext.NAMESPACE_URI,
            ArtifactNamespaceContext.NAMESPACE_PREFIX);

        Range range = gauge.getRange();

        Element riverEl = cr.create("river");
        cr.addAttr(riverEl, "name", river.getName());

        Element gaugeEl = cr.create("gauge");
        cr.addAttr(gaugeEl, "name", gauge.getName());
        cr.addAttr(gaugeEl, "from", range.getA().toString());
        cr.addAttr(gaugeEl, "to", range.getB().toString());

        root.appendChild(riverEl);
        root.appendChild(gaugeEl);
    }


    protected void appendMainValues(
        Document        doc,
        Element         root,
        List<MainValue> mainValues,
        Object          context)
    {
        logger.debug("MainValuesService.appendMainValues");

        ElementCreator cr = new ElementCreator(
            doc,
            ArtifactNamespaceContext.NAMESPACE_URI,
            ArtifactNamespaceContext.NAMESPACE_PREFIX);

        Element list = cr.create("mainvalues");

        for (MainValue mainValue: mainValues) {
            Element newEl = buildMainValueElement(doc, mainValue, context);

            if (newEl != null) {
                list.appendChild(newEl);
            }
        }

        root.appendChild(list);
    }


    /**
     * This method builds a concrete mainvalue element. This element consists of
     * three attributes: the value, its name and its type.
     *
     * @param doc The owner document.
     * @param mainValue The mainvalue.
     * @param context The context object.
     *
     * @return a mainvalue element.
     */
    protected Element buildMainValueElement(
        Document  doc,
        MainValue mainValue,
        Object    context)
    {
        ElementCreator cr = new ElementCreator(
            doc,
            ArtifactNamespaceContext.NAMESPACE_URI,
            ArtifactNamespaceContext.NAMESPACE_PREFIX);

        NamedMainValue namedMainValue = mainValue.getMainValue();
        MainValueType  mainValueType  = namedMainValue.getType();

        Element el = cr.create("mainvalue");

        cr.addAttr(el, "value", mainValue.getValue().toString());
        cr.addAttr(el, "name", namedMainValue.getName());
        cr.addAttr(el, "type", mainValueType.getName());

        return el;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org