view artifacts/src/main/java/org/dive4elements/river/artifacts/services/AbstractMainValuesService.java @ 9415:9744ce3c3853

Rework of fixanalysis computation and dWt and WQ facets. Got rid of strange remapping and bitshifting code by explicitely saving the column information and using it in the facets. The facets also put the valid station range into their xml-metadata
author gernotbelger
date Thu, 16 Aug 2018 16:27:53 +0200
parents bc9a45d2b1fa
children
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */

package org.dive4elements.river.artifacts.services;

import static org.dive4elements.river.backend.utils.EpsilonComparator.CMP;

import java.util.List;

import org.apache.log4j.Logger;
import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
import org.dive4elements.artifacts.common.utils.XMLUtils;
import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
import org.dive4elements.river.artifacts.model.RiverFactory;
import org.dive4elements.river.model.Gauge;
import org.dive4elements.river.model.MainValue;
import org.dive4elements.river.model.MainValueType;
import org.dive4elements.river.model.NamedMainValue;
import org.dive4elements.river.model.OfficialLine;
import org.dive4elements.river.model.Range;
import org.dive4elements.river.model.River;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
abstract class AbstractMainValuesService extends D4EService {

    private static final long serialVersionUID = 1L;

    public static final class MainValuesServiceException extends Exception {

        private static final long serialVersionUID = 1L;

        public MainValuesServiceException(final String message) {
            super(message);
        }
    }

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

    /** XPath that points to the river definition of the incoming request. */

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

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

    protected static final Document error(final String msg) {
        log.debug(msg);
        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 static final River getRequestedRiver(final Document data, final String XPATH_RIVER) throws MainValuesServiceException {
        log.debug("MainValuesService.getRequestedRiver");

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

        if (riverStr != null && (riverStr = riverStr.trim()).length() > 0)
            return RiverFactory.getRiver(riverStr);

        throw new MainValuesServiceException("no river found.");
    }

    protected static final Gauge getRequestedGauge(final Document data, final River river) throws MainValuesServiceException {

        final double[] minmax = getRequestedStartEnd(data, river);
        final Gauge gauge = river.determineRefGauge(minmax, CMP.compare(minmax[0], minmax[1]) != 0);
        if (gauge == null)
            throw new MainValuesServiceException("no gauge found.");

        return gauge;
    }

    /**
     * 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.
     */
    public static double[] getRequestedStartEnd(final Document data, final River river) {
        log.debug("MainValuesService.getStartEnd");

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

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

        if (startStr == null || endStr == null) {
            return river.determineMinMaxDistance();
        }

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

            if (log.isDebugEnabled()) {
                log.debug("Found start: " + start);
                log.debug("Found end: " + end);
            }

            return new double[] { start, end };
        }
        catch (final NumberFormatException nfe) {
            log.warn(nfe, nfe);
            return river.determineMinMaxDistance();
        }
    }

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

        final Document doc = XMLUtils.newDocument();

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

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

        doc.appendChild(rootEl);

        appendMetaInformation(doc, rootEl, river, gauge, context);
        appendMainValues(doc, rootEl, mainValues, river.getId(), 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.
     */
    static void appendMetaInformation(final Document doc, final Element root, final River river, final Gauge gauge, final Object context) {
        log.debug("MainValuesService.appendMetaInformation");

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

        final Range range = gauge.getRange();

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

        final 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);
    }

    /** Checks i a main value has an official associated, */
    private static boolean hasOfficialLine(final NamedMainValue nmv, final Integer riverId) {
        for (final OfficialLine ol : nmv.getOfficialLines()) {
            if (ol.getWstColumn().getWst().getRiver().getId().equals(riverId)) {
                return true;
            }
        }
        return false;
    }

    /** Append xml representation of main values to document. */
    private void appendMainValues(final Document doc, final Element root, final List<MainValue> mainValues, final Integer riverId, final Object context) {
        log.debug("MainValuesService.appendMainValues");

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

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

        for (final MainValue mainValue : mainValues) {
            final Element newEl = buildMainValueElement(doc, mainValue, riverId, 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.
     */
    private Element buildMainValueElement(final Document doc, final MainValue mainValue, final Integer riverId, final Object context) {
        final ElementCreator cr = new ElementCreator(doc, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX);

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

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

        cr.addAttr(el, "value", mainValue.getValue().toString());
        cr.addAttr(el, "name", namedMainValue.getName());
        cr.addAttr(el, "type", mainValueType.getName());
        if (mainValue.getTimeInterval() != null) {
            if (mainValue.getTimeInterval().getStartTime() != null) {
                cr.addAttr(el, "starttime", Long.toString(mainValue.getTimeInterval().getStartTime().getTime()));
            }
            if (mainValue.getTimeInterval().getStopTime() != null) {
                cr.addAttr(el, "stoptime", Long.toString(mainValue.getTimeInterval().getStopTime().getTime()));
            }
        }

        if (hasOfficialLine(namedMainValue, riverId)) {
            cr.addAttr(el, "official", "true");
        }

        return el;
    }
}

http://dive4elements.wald.intevation.org