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 :