ingo@301: package de.intevation.flys.artifacts.services;
ingo@301: 
ingo@301: import java.math.BigDecimal;
sascha@644: import java.util.Iterator;
ingo@301: 
ingo@301: import org.apache.log4j.Logger;
ingo@301: 
ingo@301: import org.w3c.dom.Document;
ingo@301: import org.w3c.dom.Element;
ingo@301: 
ingo@301: import de.intevation.artifacts.CallMeta;
sascha@966: import de.intevation.artifacts.GlobalContext;
ingo@301: 
ingo@301: import de.intevation.artifacts.common.ArtifactNamespaceContext;
ingo@301: import de.intevation.artifacts.common.utils.XMLUtils;
ingo@301: 
ingo@301: import de.intevation.flys.model.Annotation;
ingo@301: import de.intevation.flys.model.Attribute;
ingo@301: import de.intevation.flys.model.Position;
ingo@301: import de.intevation.flys.model.Range;
ingo@686: import de.intevation.flys.model.Edge;
ingo@301: 
ingo@301: import de.intevation.flys.artifacts.model.AnnotationsFactory;
ingo@301: 
sascha@644: import de.intevation.flys.artifacts.cache.CacheFactory;
sascha@644: 
sascha@644: import net.sf.ehcache.Cache;
sascha@644: 
ingo@301: /**
ingo@301:  * This service provides information about distances of a specified river.
ingo@301:  *
ingo@301:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
ingo@301:  */
ingo@1631: public class DistanceInfoService extends FLYSService {
ingo@301: 
ingo@922:     private static enum DistanceFilter {
ingo@922:         NONE, LOCATIONS, DISTANCES
ingo@922:     }
ingo@922: 
felix@1070:     /** The logger used in this service. */
ingo@301:     private static Logger logger = Logger.getLogger(DistanceInfoService.class);
ingo@301: 
sascha@644:     public static final String CACHE_NAME = "service-distanceinfo";
sascha@644: 
sascha@644:     public static final String RIVER_XPATH = "/art:river/text()";
sascha@644: 
ingo@922:     public static final String FILTER_XPATH = "/art:river/art:filter/text()";
ingo@922: 
ingo@301: 
ingo@301:     /**
ingo@301:      * The default constructor.
ingo@301:      */
ingo@301:     public DistanceInfoService() {
ingo@301:     }
ingo@301: 
ingo@301: 
sascha@966:     @Override
ingo@1631:     public Document doProcess(
sascha@966:         Document      data,
sascha@966:         GlobalContext globalContext,
sascha@966:         CallMeta      callMeta
sascha@966:     ) {
ingo@301:         logger.debug("DistanceInfoService.process");
ingo@301: 
ingo@301:         String river = XMLUtils.xpathString(
sascha@644:             data, RIVER_XPATH, ArtifactNamespaceContext.INSTANCE);
ingo@301: 
ingo@922:         String filter  = XMLUtils.xpathString(
ingo@922:             data, FILTER_XPATH, ArtifactNamespaceContext.INSTANCE);
ingo@922: 
sascha@644:         if (river == null || (river = river.trim()).length() == 0) {
ingo@301:             logger.warn("No river specified. Cannot return distance info!");
sascha@644:             return XMLUtils.newDocument();
ingo@301:         }
ingo@301: 
ingo@301:         logger.debug("Search distances for river: " + river);
ingo@301: 
sascha@644:         Cache cache = CacheFactory.getCache(CACHE_NAME);
sascha@644: 
sascha@644:         if (cache == null) {
sascha@644:             logger.debug("no cache configured for distance info");
ingo@922:             return getUncached(river, filter);
sascha@644:         }
sascha@644: 
ingo@922: 
ingo@922:         String key = getCacheKey(river, filter);
ingo@922: 
ingo@922:         net.sf.ehcache.Element element = cache.get(key);
sascha@644: 
sascha@644:         if (element != null) {
sascha@644:             logger.debug("distance info found in cache");
sascha@644:             return (Document)element.getValue();
sascha@644:         }
sascha@644: 
ingo@922:         Document result = getUncached(river, filter);
sascha@644: 
ingo@922:         element = new net.sf.ehcache.Element(key, result);
sascha@644: 
sascha@644:         logger.debug("store distance info found into cache");
sascha@644: 
sascha@644:         cache.put(element);
sascha@644: 
sascha@644:         return result;
sascha@644:     }
sascha@644: 
ingo@922: 
ingo@922:     protected String getCacheKey(String river, String filtertype) {
ingo@922:         return filtertype != null && filtertype.length() > 0
ingo@922:             ? river + "_" + filtertype
ingo@922:             : river;
ingo@922:     }
ingo@922: 
ingo@922: 
ingo@922:     protected Document getUncached(String river, String filtertype) {
sascha@644: 
sascha@644:         Document result = XMLUtils.newDocument();
sascha@644: 
ingo@1631:         Iterator<Annotation> iter =
ingo@1631:             AnnotationsFactory.getAnnotationsIterator(river);
ingo@922: 
ingo@1631:         Element all = result.createElement("distances");
ingo@922: 
ingo@1631:         DistanceFilter filter = getDistanceFilter(filtertype);
sascha@314: 
ingo@1631:         while (iter.hasNext()) {
ingo@1631:             Annotation a = iter.next();
ingo@1631:             Element distance = buildDistanceNode(result, a, filter);
ingo@1631: 
ingo@1631:             if (distance != null) {
ingo@1631:                 all.appendChild(distance);
ingo@1631:             }
ingo@301:         }
ingo@1631: 
ingo@1631:         result.appendChild(all);
ingo@301: 
ingo@301:         return result;
ingo@301:     }
ingo@301: 
ingo@301: 
ingo@922:     protected static DistanceFilter getDistanceFilter(String type) {
ingo@922:         if (type.equals("locations")) {
ingo@922:             logger.debug("Found 'location' filter.");
ingo@922:             return DistanceFilter.LOCATIONS;
ingo@922:         }
ingo@922:         else if (type.equals("distances")) {
ingo@922:             logger.debug("Found 'distances' filter.");
ingo@922:             return DistanceFilter.DISTANCES;
ingo@922:         }
ingo@922: 
ingo@922:         logger.debug("Do not use any filter at all.");
ingo@922: 
ingo@922:         return DistanceFilter.NONE;
ingo@922:     }
ingo@922: 
ingo@922: 
ingo@301:     /**
felix@1070:      * Builds an Element for a distance info.
ingo@301:      *
ingo@301:      * @param anno The Annotation that provides information about the distance.
ingo@301:      *
ingo@301:      * @return an Element that contains information about a distance.
ingo@301:      */
ingo@686:     protected static Element buildDistanceNode(
ingo@922:         Document       document,
ingo@922:         Annotation     anno,
ingo@922:         DistanceFilter filter
ingo@686:     ) {
ingo@686:         Position   pos   = anno.getPosition();
ingo@686:         Range      range = anno.getRange();
ingo@686:         Attribute  attr  = anno.getAttribute();
ingo@686:         Edge       edge  = anno.getEdge();
ingo@686:         BigDecimal a     = range.getA();
ingo@686:         BigDecimal b     = range.getB();
ingo@301: 
ingo@922:         if (b == null && filter == DistanceFilter.DISTANCES) {
ingo@922:             return null;
ingo@922:         }
ingo@922: 
ingo@922:         if (b != null && filter == DistanceFilter.LOCATIONS) {
ingo@922:             return null;
ingo@922:         }
ingo@922: 
ingo@686:         Element distance = document.createElement("distance");
ingo@301: 
ingo@686:         distance.setAttribute("description", pos.getValue());
ingo@686: 
ingo@686:         String riverSide = attr.getValue();
ingo@686: 
ingo@686:         if (riverSide != null && riverSide.length() > 0) {
ingo@686:             distance.setAttribute("riverside", riverSide);
ingo@686:         }
ingo@686: 
ingo@686:         if (a != null) {
ingo@686:             distance.setAttribute("from", a.toString());
ingo@686:         }
ingo@686:         if (b != null) {
ingo@686:             distance.setAttribute("to", b.toString());
ingo@686:         }
ingo@686:         if (edge != null) {
ingo@686:             BigDecimal bottom = edge.getBottom();
ingo@686:             BigDecimal top    = edge.getTop();
ingo@686:             if (bottom != null) {
ingo@686:                 distance.setAttribute("bottom", bottom.toString());
ingo@686:             }
ingo@686:             if (top != null) {
ingo@686:                 distance.setAttribute("top", top.toString());
ingo@686:             }
ingo@686:         }
ingo@301: 
ingo@301:         return distance;
ingo@301:     }
ingo@301: }
ingo@301: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :