view flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java @ 2089:0da8874bd378

Added initial state to map artifact to be able to advance and step back. The map artifact overrides describe() to have the complete UI information in the describe response document. flys-artifacts/trunk@3613 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Raimund Renkert <raimund.renkert@intevation.de>
date Fri, 06 Jan 2012 12:02:10 +0000
parents 26e19cdaed5e
children e92bc9b0ca1d
line wrap: on
line source
package de.intevation.flys.artifacts.services;

import java.math.BigDecimal;
import java.util.Iterator;

import org.apache.log4j.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import de.intevation.artifacts.CallMeta;
import de.intevation.artifacts.GlobalContext;

import de.intevation.artifacts.common.ArtifactNamespaceContext;
import de.intevation.artifacts.common.utils.XMLUtils;

import de.intevation.flys.model.Annotation;
import de.intevation.flys.model.Attribute;
import de.intevation.flys.model.Position;
import de.intevation.flys.model.Range;
import de.intevation.flys.model.Edge;

import de.intevation.flys.artifacts.model.AnnotationsFactory;

import de.intevation.flys.artifacts.cache.CacheFactory;

import net.sf.ehcache.Cache;

/**
 * This service provides information about distances of a specified river.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class DistanceInfoService extends FLYSService {

    private static enum DistanceFilter {
        NONE, LOCATIONS, DISTANCES
    }

    /** The logger used in this service. */
    private static Logger logger = Logger.getLogger(DistanceInfoService.class);

    public static final String CACHE_NAME = "service-distanceinfo";

    public static final String RIVER_XPATH = "/art:river/text()";

    public static final String FILTER_XPATH = "/art:river/art:filter/text()";


    /**
     * The default constructor.
     */
    public DistanceInfoService() {
    }


    @Override
    public Document doProcess(
        Document      data,
        GlobalContext globalContext,
        CallMeta      callMeta
    ) {
        logger.debug("DistanceInfoService.process");

        String river = XMLUtils.xpathString(
            data, RIVER_XPATH, ArtifactNamespaceContext.INSTANCE);

        String filter  = XMLUtils.xpathString(
            data, FILTER_XPATH, ArtifactNamespaceContext.INSTANCE);

        if (river == null || (river = river.trim()).length() == 0) {
            logger.warn("No river specified. Cannot return distance info!");
            return XMLUtils.newDocument();
        }

        logger.debug("Search distances for river: " + river);

        Cache cache = CacheFactory.getCache(CACHE_NAME);

        if (cache == null) {
            logger.debug("no cache configured for distance info");
            return getUncached(river, filter);
        }


        String key = getCacheKey(river, filter);

        net.sf.ehcache.Element element = cache.get(key);

        if (element != null) {
            logger.debug("distance info found in cache");
            return (Document)element.getValue();
        }

        Document result = getUncached(river, filter);

        element = new net.sf.ehcache.Element(key, result);

        logger.debug("store distance info found into cache");

        cache.put(element);

        return result;
    }


    protected String getCacheKey(String river, String filtertype) {
        return filtertype != null && filtertype.length() > 0
            ? river + "_" + filtertype
            : river;
    }


    protected Document getUncached(String river, String filtertype) {

        Document result = XMLUtils.newDocument();

        Iterator<Annotation> iter =
            AnnotationsFactory.getAnnotationsIterator(river);

        Element all = result.createElement("distances");

        DistanceFilter filter = getDistanceFilter(filtertype);

        while (iter.hasNext()) {
            Annotation a = iter.next();
            Element distance = buildDistanceNode(result, a, filter);

            if (distance != null) {
                all.appendChild(distance);
            }
        }

        result.appendChild(all);

        return result;
    }


    protected static DistanceFilter getDistanceFilter(String type) {
        if (type.equals("locations")) {
            logger.debug("Found 'location' filter.");
            return DistanceFilter.LOCATIONS;
        }
        else if (type.equals("distances")) {
            logger.debug("Found 'distances' filter.");
            return DistanceFilter.DISTANCES;
        }

        logger.debug("Do not use any filter at all.");

        return DistanceFilter.NONE;
    }


    /**
     * Builds an Element for a distance info.
     *
     * @param anno The Annotation that provides information about the distance.
     *
     * @return an Element that contains information about a distance.
     */
    protected static Element buildDistanceNode(
        Document       document,
        Annotation     anno,
        DistanceFilter filter
    ) {
        Position   pos   = anno.getPosition();
        Range      range = anno.getRange();
        Attribute  attr  = anno.getAttribute();
        Edge       edge  = anno.getEdge();
        BigDecimal a     = range.getA();
        BigDecimal b     = range.getB();

        if (b == null && filter == DistanceFilter.DISTANCES) {
            return null;
        }

        if (b != null && filter == DistanceFilter.LOCATIONS) {
            return null;
        }

        Element distance = document.createElement("distance");

        distance.setAttribute("description", pos.getValue());

        String riverSide = attr.getValue();

        if (riverSide != null && riverSide.length() > 0) {
            distance.setAttribute("riverside", riverSide);
        }

        if (a != null) {
            distance.setAttribute("from", a.toString());
        }
        if (b != null) {
            distance.setAttribute("to", b.toString());
        }
        if (edge != null) {
            BigDecimal bottom = edge.getBottom();
            BigDecimal top    = edge.getTop();
            if (bottom != null) {
                distance.setAttribute("bottom", bottom.toString());
            }
            if (top != null) {
                distance.setAttribute("top", top.toString());
            }
        }

        return distance;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org