view flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java @ 1839:c3b44da22a3a

Minor refactoring in preparation of generation of interpolators (WstValueTable) for static WQKms. flys-artifacts/trunk@3175 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Mon, 07 Nov 2011 12:37:41 +0000
parents f7d890f4855f
children 4781096f31f8
line wrap: on
line source
package de.intevation.flys.artifacts.services;

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

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

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

import de.intevation.flys.backend.SessionHolder;

import de.intevation.flys.model.CrossSection;
import de.intevation.flys.model.CrossSectionLine;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;

import java.util.concurrent.ConcurrentSkipListMap;

import net.sf.ehcache.Cache;

import org.apache.log4j.Logger;

import org.hibernate.Query;
import org.hibernate.Session;

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

public class CrossSectionKMService
extends      FLYSService
{
    private static Logger logger =
        Logger.getLogger(CrossSectionKMService.class);

    public static final String CACHE_NAME = "cross-section-kms";

    public CrossSectionKMService() {
    }

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

        NodeList crossSectionNodes =
            data.getElementsByTagName("cross-section");

        Cache cache = CacheFactory.getCache(CACHE_NAME);

        Document document = XMLUtils.newDocument();

        Element all = document.createElement("cross-sections");

        for (int i = 0, CS = crossSectionNodes.getLength(); i < CS; ++i) {
            Element crossSectionElement = (Element)crossSectionNodes.item(i);

            String idString = crossSectionElement.getAttribute("id");
            String kmString = crossSectionElement.getAttribute("km");
            String neighborsString = crossSectionElement.getAttribute("n");

            if (idString.length() == 0 || kmString.length() == 0) {
                logger.debug("missing attributes in cross-section element");
                continue;
            }

            double  km;
            Integer crossSectionId;
            int     N = 2;

            try {
                km             = Double.parseDouble(kmString);
                crossSectionId = Integer.valueOf(idString);

                if (neighborsString.length() > 0) {
                    N = Integer.parseInt(neighborsString);
                }
            }
            catch (NumberFormatException nfe) {
                logger.debug("converting number failed", nfe);
                continue;
            }

            NavigableMap<Double, Integer> map;

            if (cache == null) {
                map = getUncached(crossSectionId);
            }
            else {
                net.sf.ehcache.Element element = cache.get(crossSectionId);
                if (element == null) {
                    map = getUncached(crossSectionId);
                    if (map != null) {
                        element = new net.sf.ehcache.Element(
                            crossSectionId, map);
                        cache.put(element);
                    }
                }
                else {
                    map = (NavigableMap<Double, Integer>)element.getValue();
                }
            }

            if (map == null) {
                logger.debug("cannot find cross section " + crossSectionId);
                continue;
            }

            Deque<Map.Entry<Double, Integer>> result =
                nearestNeighbors(map, km, N);

            if (!result.isEmpty()) {
                Element csE = document.createElement("cross-section");
                csE.setAttribute("id", idString);
                for (Map.Entry<Double, Integer> entry: result) {
                    Element lineE = document.createElement("line");
                    lineE.setAttribute(
                        "line-id", String.valueOf(entry.getValue()));
                    lineE.setAttribute(
                        "km", String.valueOf(entry.getKey()));
                    csE.appendChild(lineE);
                }
                all.appendChild(csE);
            }
        }

        document.appendChild(all);

        return document;
    }

    public static Deque<Map.Entry<Double, Integer>> nearestNeighbors(
        NavigableMap<Double, Integer> map,
        double                        km,
        int                           N
    ) {
        Deque<Map.Entry<Double, Integer>> result =
            new ArrayDeque<Map.Entry<Double, Integer>>(2*N);

        int i = 0;
        for (Map.Entry<Double, Integer> entry:
             map.headMap(km, false).descendingMap().entrySet()) {
            if (i++ >= N) {
                break;
            }
            result.addFirst(entry);
        }

        i = 0;
        for (Map.Entry<Double, Integer> entry:
             map.tailMap(km, false).entrySet()) {
            if (i++ >= N) {
                break;
            }
            result.addLast(entry);
        }

        return result;
    }

    public static NavigableMap<Double, Integer> getUncached(
        Integer crossSectionId
    ) {
        NavigableMap<Double, Integer> result =
            new ConcurrentSkipListMap<Double, Integer>();

        Session session = SessionHolder.HOLDER.get();
        Query query = session.createQuery(
            "from CrossSection where id=:id");
        query.setParameter("id", crossSectionId);

        List<CrossSection> crossSections = query.list();
        if (crossSections.isEmpty()) {
            return null;
        }

        CrossSection crossSection = crossSections.get(0);
        List<CrossSectionLine> lines = crossSection.getLines();

        for (CrossSectionLine line: lines) {
            Double  km = line.getKm().doubleValue();
            Integer id = line.getId();
            result.put(km, id);
        }

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

http://dive4elements.wald.intevation.org