Mercurial > dive4elements > river
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 : |