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 Ingo Weinzierl 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 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 :