sascha@1749: package de.intevation.flys.artifacts.services; sascha@1749: sascha@1749: import de.intevation.artifacts.CallMeta; sascha@1749: import de.intevation.artifacts.GlobalContext; sascha@1749: sascha@1749: import de.intevation.artifacts.common.utils.XMLUtils; sascha@1749: sascha@1749: import de.intevation.flys.artifacts.cache.CacheFactory; sascha@1749: sascha@1749: import de.intevation.flys.backend.SessionHolder; sascha@1749: sascha@1749: import de.intevation.flys.model.CrossSection; sascha@1749: import de.intevation.flys.model.CrossSectionLine; sascha@1749: sascha@1749: import java.util.ArrayDeque; sascha@1749: import java.util.Deque; sascha@1749: import java.util.List; sascha@1749: import java.util.Map; sascha@1749: import java.util.NavigableMap; sascha@1749: sascha@1749: import java.util.concurrent.ConcurrentSkipListMap; sascha@1749: sascha@1749: import net.sf.ehcache.Cache; sascha@1749: sascha@1749: import org.apache.log4j.Logger; sascha@1749: sascha@1749: import org.hibernate.Query; sascha@1749: import org.hibernate.Session; sascha@1749: sascha@1749: import org.w3c.dom.Document; sascha@1749: import org.w3c.dom.Element; sascha@1749: import org.w3c.dom.NodeList; sascha@1749: sascha@1749: public class CrossSectionKMService sascha@1749: extends FLYSService sascha@1749: { sascha@1749: private static Logger logger = sascha@1749: Logger.getLogger(CrossSectionKMService.class); sascha@1749: sascha@1749: public static final String CACHE_NAME = "cross-section-kms"; sascha@1749: sascha@1749: public CrossSectionKMService() { sascha@1749: } sascha@1749: sascha@1749: @Override sascha@1749: public Document doProcess( sascha@1749: Document data, sascha@1749: GlobalContext globalContext, sascha@1749: CallMeta callMeta sascha@1749: ) { sascha@1749: logger.debug("CrossSectionKMService.doProcess"); sascha@1749: sascha@1749: NodeList crossSectionNodes = sascha@1749: data.getElementsByTagName("cross-section"); sascha@1749: sascha@1749: Cache cache = CacheFactory.getCache(CACHE_NAME); sascha@1749: sascha@1749: Document document = XMLUtils.newDocument(); sascha@1749: sascha@1749: Element all = document.createElement("cross-sections"); sascha@1749: sascha@1749: for (int i = 0, CS = crossSectionNodes.getLength(); i < CS; ++i) { sascha@1749: Element crossSectionElement = (Element)crossSectionNodes.item(i); sascha@1749: sascha@1749: String idString = crossSectionElement.getAttribute("id"); sascha@1749: String kmString = crossSectionElement.getAttribute("km"); sascha@1749: String neighborsString = crossSectionElement.getAttribute("n"); sascha@1749: sascha@1749: if (idString.length() == 0 || kmString.length() == 0) { sascha@1749: logger.debug("missing attributes in cross-section element"); sascha@1749: continue; sascha@1749: } sascha@1749: sascha@1749: double km; sascha@1749: Integer crossSectionId; sascha@1749: int N = 2; sascha@1749: sascha@1749: try { sascha@1749: km = Double.parseDouble(kmString); sascha@1749: crossSectionId = Integer.valueOf(idString); sascha@1749: sascha@1749: if (neighborsString.length() > 0) { sascha@1749: N = Integer.parseInt(neighborsString); sascha@1749: } sascha@1749: } sascha@1749: catch (NumberFormatException nfe) { sascha@1749: logger.debug("converting number failed", nfe); sascha@1749: continue; sascha@1749: } sascha@1749: sascha@1749: NavigableMap map; sascha@1749: sascha@1749: if (cache == null) { sascha@1749: map = getUncached(crossSectionId); sascha@1749: } sascha@1749: else { sascha@1749: net.sf.ehcache.Element element = cache.get(crossSectionId); sascha@1749: if (element == null) { sascha@1749: map = getUncached(crossSectionId); sascha@1749: if (map != null) { sascha@1749: element = new net.sf.ehcache.Element( sascha@1749: crossSectionId, map); sascha@1749: cache.put(element); sascha@1749: } sascha@1749: } sascha@1749: else { sascha@1749: map = (NavigableMap)element.getValue(); sascha@1749: } sascha@1749: } sascha@1749: sascha@1749: if (map == null) { sascha@1749: logger.debug("cannot find cross section " + crossSectionId); sascha@1749: continue; sascha@1749: } sascha@1749: sascha@1749: Deque> result = sascha@1749: nearestNeighbors(map, km, N); sascha@1749: sascha@1749: if (!result.isEmpty()) { sascha@1749: Element csE = document.createElement("cross-section"); sascha@1749: csE.setAttribute("id", idString); sascha@1749: for (Map.Entry entry: result) { sascha@1749: Element lineE = document.createElement("line"); sascha@1749: lineE.setAttribute( sascha@1749: "line-id", String.valueOf(entry.getValue())); sascha@1749: lineE.setAttribute( sascha@1749: "km", String.valueOf(entry.getKey())); sascha@1749: csE.appendChild(lineE); sascha@1749: } sascha@1749: all.appendChild(csE); sascha@1749: } sascha@1749: } sascha@1749: sascha@1749: document.appendChild(all); sascha@1749: sascha@1749: return document; sascha@1749: } sascha@1749: sascha@1749: public static Deque> nearestNeighbors( sascha@1749: NavigableMap map, sascha@1749: double km, sascha@1749: int N sascha@1749: ) { sascha@1749: Deque> result = sascha@1749: new ArrayDeque>(2*N); sascha@1749: sascha@1749: int i = 0; sascha@1749: for (Map.Entry entry: sascha@1749: map.headMap(km, false).descendingMap().entrySet()) { sascha@1749: if (i++ >= N) { sascha@1749: break; sascha@1749: } sascha@1749: result.addFirst(entry); sascha@1749: } sascha@1749: sascha@1749: i = 0; sascha@1749: for (Map.Entry entry: sascha@1749: map.tailMap(km, false).entrySet()) { sascha@1749: if (i++ >= N) { sascha@1749: break; sascha@1749: } sascha@1749: result.addLast(entry); sascha@1749: } sascha@1749: sascha@1749: return result; sascha@1749: } sascha@1749: sascha@1749: public static NavigableMap getUncached( sascha@1749: Integer crossSectionId sascha@1749: ) { sascha@1749: NavigableMap result = sascha@1749: new ConcurrentSkipListMap(); sascha@1749: sascha@1749: Session session = SessionHolder.HOLDER.get(); sascha@1749: Query query = session.createQuery( sascha@1749: "from CrossSection where id=:id"); sascha@1749: query.setParameter("id", crossSectionId); sascha@1749: sascha@1749: List crossSections = query.list(); sascha@1749: if (crossSections.isEmpty()) { sascha@1749: return null; sascha@1749: } sascha@1749: sascha@1749: CrossSection crossSection = crossSections.get(0); sascha@1749: List lines = crossSection.getLines(); sascha@1749: sascha@1749: for (CrossSectionLine line: lines) { sascha@1749: Double km = line.getKm().doubleValue(); sascha@1749: Integer id = line.getId(); sascha@1749: result.put(km, id); sascha@1749: } sascha@1749: sascha@1749: return result; sascha@1749: } sascha@1749: } sascha@1749: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :