comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/CrossSectionKMService.java @ 1749:f7d890f4855f

Added Service Service to lookup the Nth nearest neighbors for a set of given cross section ids and kms. flys-artifacts/trunk@3049 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Thu, 20 Oct 2011 17:14:24 +0000
parents
children 4781096f31f8
comparison
equal deleted inserted replaced
1748:d56b94325bec 1749:f7d890f4855f
1 package de.intevation.flys.artifacts.services;
2
3 import de.intevation.artifacts.CallMeta;
4 import de.intevation.artifacts.GlobalContext;
5
6 import de.intevation.artifacts.common.utils.XMLUtils;
7
8 import de.intevation.flys.artifacts.cache.CacheFactory;
9
10 import de.intevation.flys.backend.SessionHolder;
11
12 import de.intevation.flys.model.CrossSection;
13 import de.intevation.flys.model.CrossSectionLine;
14
15 import java.util.ArrayDeque;
16 import java.util.Deque;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.NavigableMap;
20
21 import java.util.concurrent.ConcurrentSkipListMap;
22
23 import net.sf.ehcache.Cache;
24
25 import org.apache.log4j.Logger;
26
27 import org.hibernate.Query;
28 import org.hibernate.Session;
29
30 import org.w3c.dom.Document;
31 import org.w3c.dom.Element;
32 import org.w3c.dom.NodeList;
33
34 public class CrossSectionKMService
35 extends FLYSService
36 {
37 private static Logger logger =
38 Logger.getLogger(CrossSectionKMService.class);
39
40 public static final String CACHE_NAME = "cross-section-kms";
41
42 public CrossSectionKMService() {
43 }
44
45 @Override
46 public Document doProcess(
47 Document data,
48 GlobalContext globalContext,
49 CallMeta callMeta
50 ) {
51 logger.debug("CrossSectionKMService.doProcess");
52
53 NodeList crossSectionNodes =
54 data.getElementsByTagName("cross-section");
55
56 Cache cache = CacheFactory.getCache(CACHE_NAME);
57
58 Document document = XMLUtils.newDocument();
59
60 Element all = document.createElement("cross-sections");
61
62 for (int i = 0, CS = crossSectionNodes.getLength(); i < CS; ++i) {
63 Element crossSectionElement = (Element)crossSectionNodes.item(i);
64
65 String idString = crossSectionElement.getAttribute("id");
66 String kmString = crossSectionElement.getAttribute("km");
67 String neighborsString = crossSectionElement.getAttribute("n");
68
69 if (idString.length() == 0 || kmString.length() == 0) {
70 logger.debug("missing attributes in cross-section element");
71 continue;
72 }
73
74 double km;
75 Integer crossSectionId;
76 int N = 2;
77
78 try {
79 km = Double.parseDouble(kmString);
80 crossSectionId = Integer.valueOf(idString);
81
82 if (neighborsString.length() > 0) {
83 N = Integer.parseInt(neighborsString);
84 }
85 }
86 catch (NumberFormatException nfe) {
87 logger.debug("converting number failed", nfe);
88 continue;
89 }
90
91 NavigableMap<Double, Integer> map;
92
93 if (cache == null) {
94 map = getUncached(crossSectionId);
95 }
96 else {
97 net.sf.ehcache.Element element = cache.get(crossSectionId);
98 if (element == null) {
99 map = getUncached(crossSectionId);
100 if (map != null) {
101 element = new net.sf.ehcache.Element(
102 crossSectionId, map);
103 cache.put(element);
104 }
105 }
106 else {
107 map = (NavigableMap<Double, Integer>)element.getValue();
108 }
109 }
110
111 if (map == null) {
112 logger.debug("cannot find cross section " + crossSectionId);
113 continue;
114 }
115
116 Deque<Map.Entry<Double, Integer>> result =
117 nearestNeighbors(map, km, N);
118
119 if (!result.isEmpty()) {
120 Element csE = document.createElement("cross-section");
121 csE.setAttribute("id", idString);
122 for (Map.Entry<Double, Integer> entry: result) {
123 Element lineE = document.createElement("line");
124 lineE.setAttribute(
125 "line-id", String.valueOf(entry.getValue()));
126 lineE.setAttribute(
127 "km", String.valueOf(entry.getKey()));
128 csE.appendChild(lineE);
129 }
130 all.appendChild(csE);
131 }
132 }
133
134 document.appendChild(all);
135
136 return document;
137 }
138
139 public static Deque<Map.Entry<Double, Integer>> nearestNeighbors(
140 NavigableMap<Double, Integer> map,
141 double km,
142 int N
143 ) {
144 Deque<Map.Entry<Double, Integer>> result =
145 new ArrayDeque<Map.Entry<Double, Integer>>(2*N);
146
147 int i = 0;
148 for (Map.Entry<Double, Integer> entry:
149 map.headMap(km, false).descendingMap().entrySet()) {
150 if (i++ >= N) {
151 break;
152 }
153 result.addFirst(entry);
154 }
155
156 i = 0;
157 for (Map.Entry<Double, Integer> entry:
158 map.tailMap(km, false).entrySet()) {
159 if (i++ >= N) {
160 break;
161 }
162 result.addLast(entry);
163 }
164
165 return result;
166 }
167
168 public static NavigableMap<Double, Integer> getUncached(
169 Integer crossSectionId
170 ) {
171 NavigableMap<Double, Integer> result =
172 new ConcurrentSkipListMap<Double, Integer>();
173
174 Session session = SessionHolder.HOLDER.get();
175 Query query = session.createQuery(
176 "from CrossSection where id=:id");
177 query.setParameter("id", crossSectionId);
178
179 List<CrossSection> crossSections = query.list();
180 if (crossSections.isEmpty()) {
181 return null;
182 }
183
184 CrossSection crossSection = crossSections.get(0);
185 List<CrossSectionLine> lines = crossSection.getLines();
186
187 for (CrossSectionLine line: lines) {
188 Double km = line.getKm().doubleValue();
189 Integer id = line.getId();
190 result.put(km, id);
191 }
192
193 return result;
194 }
195 }
196 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org