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.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 <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
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<MainValue> 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 <i>river</i> 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 <i>gauge</i>.
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<MainValue> 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<MainValue> 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<MainValue> 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<MainValue> 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 :