comparison flys-backend/src/main/java/de/intevation/flys/model/FastAnnotations.java @ 2382:c5791de0c495

Added meachnism to backend to fetch all annotation related data in one go. flys-backend/trunk@3722 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Thu, 19 Jan 2012 13:36:06 +0000
parents
children 07c96cd39360
comparison
equal deleted inserted replaced
2381:aa777d1aba38 2382:c5791de0c495
1 package de.intevation.flys.model;
2
3 import java.util.Comparator;
4 import java.util.ArrayList;
5 import java.util.List;
6 import java.util.Arrays;
7 import java.util.HashMap;
8 import java.util.Iterator;
9 import java.util.NoSuchElementException;
10
11 import java.io.Serializable;
12
13 import org.hibernate.Session;
14 import org.hibernate.SQLQuery;
15
16 import org.hibernate.type.StandardBasicTypes;
17
18 import de.intevation.flys.backend.SessionHolder;
19
20 public class FastAnnotations
21 implements Serializable
22 {
23 public static final String SQL_BY_RIVER_NAME =
24 "SELECT r.a AS a, r.b AS b, p.value AS position, " +
25 "at.value AS attribute, ant.name AS name, " +
26 "e.top AS top, e.bottom AS bottom " +
27 "FROM annotations an " +
28 "JOIN ranges r " +
29 "ON an.range_id = r.id " +
30 "JOIN attributes at " +
31 "ON an.attribute_id = at.id " +
32 "JOIN positions p " +
33 "ON an.position_id = p.id " +
34 "JOIN rivers riv " +
35 "ON r.river_id = riv.id " +
36 "LEFT JOIN annotation_types ant " +
37 "ON an.type_id = ant.id " +
38 "LEFT JOIN edges e " +
39 "ON an.edge_id = e.id " +
40 "WHERE riv.name = :river_name " +
41 "ORDER BY r.a";
42
43 public static final String SQL_BY_RIVER_ID =
44 "SELECT r.a AS a, r.b AS b, p.value AS position, " +
45 "at.value AS attribute, ant.name AS name, " +
46 "e.top AS top, e.bottom AS bottom " +
47 "FROM annotations an " +
48 "JOIN ranges r " +
49 "ON an.range_id = r.id " +
50 "JOIN attributes at " +
51 "ON an.attribute_id = at.id " +
52 "JOIN positions p " +
53 "ON an.position_id = p.id " +
54 "LEFT JOIN annotation_types ant " +
55 "ON an.type_id = ant.id " +
56 "LEFT JOIN edges e " +
57 "ON an.edge_id = e.id " +
58 "WHERE r.id = :river_id " +
59 "ORDER BY r.a";
60
61 public static final double EPSILON = 1e-5;
62
63 public static final Comparator<Annotation> KM_CMP =
64 new Comparator<Annotation>() {
65 @Override
66 public int compare(Annotation a, Annotation b) {
67 double diff = a.a - b.a;
68 if (diff < -EPSILON) return -1;
69 if (diff > +EPSILON) return +1;
70 return 0;
71 }
72 };
73
74 public static final class Annotation
75 implements Serializable
76 {
77 private double a;
78 private double b;
79 private String position;
80 private String attribute;
81 private String name;
82 private double top;
83 private double bottom;
84
85 public Annotation() {
86 }
87
88 public Annotation(double a) {
89 this.a = a;
90 }
91
92 public Annotation(
93 double a,
94 double b,
95 String position,
96 String attribute,
97 String name,
98 double top,
99 double bottom
100 ) {
101 this.a = a;
102 this.b = b;
103 this.position = position;
104 this.attribute = attribute;
105 this.name = name;
106 this.top = top;
107 this.bottom = bottom;
108 }
109
110 public double getA() {
111 return a;
112 }
113
114 public double getB() {
115 return b;
116 }
117
118 public String getPosition() {
119 return position;
120 }
121
122 public String getAttribute() {
123 return attribute;
124 }
125
126 public String getName() {
127 return name;
128 }
129
130 public double getTop() {
131 return top;
132 }
133
134 public double getBottom() {
135 return bottom;
136 }
137 } // class Serializable
138
139 public interface Filter {
140
141 boolean accept(Annotation annotation);
142
143 } // interface Filter
144
145 public static final Filter ALL = new Filter() {
146 @Override
147 public boolean accept(Annotation annotation) {
148 return true;
149 }
150 };
151
152 public static final Filter IS_POINT = new Filter() {
153 @Override
154 public boolean accept(Annotation annotation) {
155 return Double.isNaN(annotation.getB());
156 }
157 };
158
159 public static final Filter IS_RANGE = new Filter() {
160 @Override
161 public boolean accept(Annotation annotation) {
162 return !Double.isNaN(annotation.getB());
163 }
164 };
165
166 private Annotation [] annotations;
167
168 public FastAnnotations() {
169 }
170
171 public FastAnnotations(Annotation [] annotations) {
172 this.annotations = annotations;
173 }
174
175 public FastAnnotations(String riverName) {
176 this(loadByRiverName(riverName));
177 }
178
179 public FastAnnotations(int riverId) {
180 this(loadByRiverId(riverId));
181 }
182
183 public FastAnnotations(Iterator<Annotation> iter) {
184 this(toArray(iter));
185 }
186
187 public int size() {
188 return annotations.length;
189 }
190
191 public Iterator<Annotation> filter(final Filter filter) {
192 return new Iterator<Annotation>() {
193
194 private int idx;
195 private Annotation current = findNext();
196
197 @Override
198 public boolean hasNext() {
199 return current != null;
200 }
201
202 @Override
203 public Annotation next() {
204 if (current == null) {
205 throw new NoSuchElementException();
206 }
207 Annotation result = current;
208 current = findNext();
209 return result;
210 }
211
212 private Annotation findNext() {
213
214 while (idx < annotations.length) {
215 Annotation annotation = annotations[idx++];
216 if (filter.accept(annotation)) {
217 return annotation;
218 }
219 }
220
221 return null;
222 }
223
224 @Override
225 public void remove() {
226 throw new UnsupportedOperationException();
227 }
228 };
229 }
230
231 public static Annotation [] toArray(Iterator<Annotation> iter) {
232
233 ArrayList<Annotation> list = new ArrayList<Annotation>();
234
235 while (iter.hasNext()) {
236 list.add(iter.next());
237 }
238
239 return list.toArray(new Annotation[list.size()]);
240 }
241
242 public Annotation findByKm(double km) {
243 Annotation key = new Annotation(km);
244 int idx = Arrays.binarySearch(annotations, key, KM_CMP);
245 return idx < 0 ? null : annotations[idx];
246 }
247
248 private static SQLQuery createQuery(String query) {
249 Session session = SessionHolder.HOLDER.get();
250
251 return session.createSQLQuery(query)
252 .addScalar("a", StandardBasicTypes.DOUBLE)
253 .addScalar("b", StandardBasicTypes.DOUBLE)
254 .addScalar("position", StandardBasicTypes.STRING)
255 .addScalar("attribute", StandardBasicTypes.STRING)
256 .addScalar("name", StandardBasicTypes.STRING)
257 .addScalar("top", StandardBasicTypes.DOUBLE)
258 .addScalar("bottom", StandardBasicTypes.DOUBLE);
259 }
260
261 private static Annotation [] buildAnnotations(List<Object []> list) {
262 Annotation [] anns = new Annotation[list.size()];
263
264 // Names are likely the same because they are a type
265 // like 'Pegel' or 'Hafen'.
266 HashMap<String, String> names = new HashMap<String, String>();
267
268 for (int i = 0; i < anns.length; ++i) {
269 Object [] data = list.get(i);
270 double a = ((Double)data[0]);
271 double b = data[1] != null ? (Double)data[1] : Double.NaN;
272 String position = (String)data[2];
273 String attribute = (String)data[3];
274 String name = (String)data[4];
275 double top = data[5] != null ? (Double)data[5] : Double.NaN;
276 double bottom = data[6] != null ? (Double)data[6] : Double.NaN;
277
278 if (name != null) {
279 String old = names.get(name);
280 if (old != null) {
281 name = old;
282 }
283 else {
284 names.put(name, name);
285 }
286 }
287
288 anns[i] = new Annotation(
289 a, b, position, attribute, name, top, bottom);
290 }
291
292 return anns;
293 }
294
295 public static Annotation [] loadByRiverName(String riverName) {
296
297 SQLQuery query = createQuery(SQL_BY_RIVER_NAME);
298
299 query.setString("river_name", riverName);
300
301 return buildAnnotations(query.list());
302 }
303
304 public static Annotation [] loadByRiverId(int riverId) {
305
306 SQLQuery query = createQuery(SQL_BY_RIVER_ID);
307
308 query.setInteger("river_id", riverId);
309
310 return buildAnnotations(query.list());
311 }
312 }
313 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org