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 org.hibernate.Session;
ingo@331: 
ingo@331: import de.intevation.artifacts.CallMeta;
ingo@331: 
ingo@331: import de.intevation.artifactdatabase.DefaultService;
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.backend.SessionHolder;
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 <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
ingo@331:  */
ingo@331: public class MainValuesService extends DefaultService {
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@331:     public static final String XPATH_START = "/art:mainvalues/art:end/text()";
ingo@331: 
ingo@331:     /** The XPath that points to the end definition of the incoming request.*/
ingo@331:     public static final String XPATH_END = "/art:mainvalues/art:start/text()";
ingo@331: 
ingo@331:     /**
ingo@331:      * The default constructor.
ingo@331:      */
ingo@331:     public MainValuesService() {
ingo@331:     }
ingo@331: 
ingo@331: 
ingo@331:     public Document process(
ingo@331:         Document data,
ingo@331:         Object   context,
ingo@331:         CallMeta callMeta)
ingo@331:     {
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@331:             List<MainValue> 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 <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: 
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 <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:      */
ingo@331:     protected List<MainValue> 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@331:         Session session = SessionHolder.acquire();
ingo@331:         try {
ingo@331:             List<MainValue> mainValues = MainValuesFactory.getMainValues(gauge);
ingo@331: 
ingo@331:             if (mainValues == null || mainValues.isEmpty()) {
ingo@331:                 throw new NullPointerException("No main values found.");
ingo@331:             }
ingo@331: 
ingo@331:             logger.debug(mainValues.size() + " main values found.");
ingo@331: 
ingo@331:             return mainValues;
ingo@331:         }
ingo@331:         finally {
ingo@331:             session.close();
ingo@331:             SessionHolder.release();
ingo@331:         }
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 :