Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/model/fixings/FixingsOverview.java @ 9415:9744ce3c3853
Rework of fixanalysis computation and dWt and WQ facets. Got rid of strange remapping and bitshifting code by explicitely saving the column information and using it in the facets.
The facets also put the valid station range into their xml-metadata
author | gernotbelger |
---|---|
date | Thu, 16 Aug 2018 16:27:53 +0200 |
parents | artifacts/src/main/java/org/dive4elements/river/artifacts/model/FixingsOverview.java@3e93f29281bc |
children |
comparison
equal
deleted
inserted
replaced
9414:096f151a0a9f | 9415:9744ce3c3853 |
---|---|
1 /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde | |
2 * Software engineering by Intevation GmbH | |
3 * | |
4 * This file is Free Software under the GNU AGPL (>=v3) | |
5 * and comes with ABSOLUTELY NO WARRANTY! Check out the | |
6 * documentation coming with Dive4Elements River for details. | |
7 */ | |
8 | |
9 package org.dive4elements.river.artifacts.model.fixings; | |
10 | |
11 import java.io.Serializable; | |
12 import java.text.SimpleDateFormat; | |
13 import java.util.ArrayList; | |
14 import java.util.Collections; | |
15 import java.util.Date; | |
16 import java.util.List; | |
17 | |
18 import org.apache.log4j.Logger; | |
19 import org.dive4elements.river.artifacts.model.GaugeFinder; | |
20 import org.dive4elements.river.artifacts.model.GaugeFinderFactory; | |
21 import org.dive4elements.river.artifacts.model.GaugeRange; | |
22 import org.dive4elements.river.artifacts.model.Range; | |
23 import org.hibernate.SQLQuery; | |
24 import org.hibernate.Session; | |
25 import org.hibernate.type.StandardBasicTypes; | |
26 import org.w3c.dom.Document; | |
27 import org.w3c.dom.Element; | |
28 | |
29 /** Generate Fixings Table overview data structure to be stored in cache. */ | |
30 public class FixingsOverview implements Serializable { | |
31 | |
32 private static final long serialVersionUID = 1L; | |
33 | |
34 static Logger log = Logger.getLogger(FixingsOverview.class); | |
35 | |
36 static final String DATE_FORMAT = "dd.MM.yyyy"; | |
37 | |
38 private static final String SQL_RIVER_ID = "SELECT" + " id AS river_id," + " km_up " + "FROM rivers " + "WHERE" + " name = :name"; | |
39 | |
40 /** All kind-2 wsts from given river. */ | |
41 private static final String SQL_FIXINGS = "SELECT" + " id AS wst_id," + " description " + "FROM wsts " + "WHERE" | |
42 + " river_id = :river_id AND kind = 2"; | |
43 | |
44 /** Helper class to store data from batching fixing columns. */ | |
45 static final class FixColumn { | |
46 int columnId; | |
47 Date startTime; | |
48 String name; | |
49 | |
50 FixColumn(final int columnId, final Date startTime, final String name) { | |
51 this.columnId = columnId; | |
52 this.startTime = startTime; | |
53 this.name = name; | |
54 } | |
55 } | |
56 | |
57 private String riverName; | |
58 | |
59 private int riverId; | |
60 | |
61 private boolean isKmUp; | |
62 | |
63 private final List<Fixing> fixings; | |
64 | |
65 private final Range extent; | |
66 | |
67 public FixingsOverview() { | |
68 this.fixings = new ArrayList<>(); | |
69 this.extent = new Range(Double.MAX_VALUE, -Double.MAX_VALUE); | |
70 } | |
71 | |
72 public FixingsOverview(final String riverName) { | |
73 this(); | |
74 this.riverName = riverName; | |
75 } | |
76 | |
77 private boolean loadRiver(final Session session) { | |
78 final SQLQuery query = session.createSQLQuery(SQL_RIVER_ID).addScalar("river_id", StandardBasicTypes.INTEGER).addScalar("km_up", | |
79 StandardBasicTypes.BOOLEAN); | |
80 | |
81 query.setString("name", this.riverName); | |
82 | |
83 final List<Object[]> list = query.list(); | |
84 | |
85 if (list.isEmpty()) { | |
86 log.warn("No river '" + this.riverName + "' found."); | |
87 return false; | |
88 } | |
89 | |
90 final Object[] row = list.get(0); | |
91 | |
92 this.riverId = (Integer) row[0]; | |
93 this.isKmUp = (Boolean) row[1]; | |
94 | |
95 return true; | |
96 } | |
97 | |
98 private void loadFixings(final Session session) { | |
99 final SQLQuery query = session.createSQLQuery(SQL_FIXINGS).addScalar("wst_id", StandardBasicTypes.INTEGER).addScalar("description", | |
100 StandardBasicTypes.STRING); | |
101 | |
102 query.setInteger("river_id", this.riverId); | |
103 | |
104 final List<Object[]> list = query.list(); | |
105 | |
106 if (list.isEmpty()) { | |
107 log.warn("River " + this.riverId + " has no fixings."); | |
108 // Its pretty fine to have no fixings. | |
109 } | |
110 | |
111 for (final Object[] row : list) { | |
112 final int wstId = (Integer) row[0]; | |
113 final String description = (String) row[1]; | |
114 final Fixing fixing = new Fixing(wstId, description); | |
115 this.fixings.add(fixing); | |
116 } | |
117 } | |
118 | |
119 private void loadFixingsColumns(final Session session) { | |
120 | |
121 final FixColumnLoader loader = new FixColumnLoader(allFixingIds(), session); | |
122 | |
123 for (final Fixing fixing : this.fixings) { | |
124 fixing.loadColumns(loader); | |
125 } | |
126 } | |
127 | |
128 private List<Integer> allFixingIds() { | |
129 final List<Integer> ids = new ArrayList<>(this.fixings.size()); | |
130 for (final Fixing fixing : this.fixings) { | |
131 ids.add(fixing.getId()); | |
132 } | |
133 return ids; | |
134 } | |
135 | |
136 private List<Integer> allColumnIds() { | |
137 final List<Integer> cIds = new ArrayList<>(); | |
138 for (final Fixing fixing : this.fixings) { | |
139 fixing.allColumnIds(cIds); | |
140 } | |
141 return cIds; | |
142 } | |
143 | |
144 private void loadFixingsColumnsKmRange(final Session session) { | |
145 | |
146 final KMRangeLoader loader = new KMRangeLoader(allColumnIds(), session); | |
147 | |
148 for (final Fixing fixing : this.fixings) { | |
149 fixing.loadColumnsKmRange(loader); | |
150 } | |
151 } | |
152 | |
153 private void loadFixingsColumnsQRanges(final Session session, final GaugeFinder gaugeFinder) { | |
154 | |
155 final ColumnQRangeLoader loader = new ColumnQRangeLoader(allColumnIds(), session); | |
156 | |
157 for (final Fixing fixing : this.fixings) { | |
158 fixing.loadColumnsQRanges(loader, gaugeFinder); | |
159 } | |
160 } | |
161 | |
162 private void adjustExtent() { | |
163 for (final Fixing fixing : this.fixings) { | |
164 fixing.adjustExtent(this.extent); | |
165 } | |
166 } | |
167 | |
168 boolean load(final Session session) { | |
169 | |
170 if (!loadRiver(session)) { | |
171 return false; | |
172 } | |
173 | |
174 final GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); | |
175 | |
176 final GaugeFinder gaugeFinder = gff.getGaugeFinder(this.riverId, this.isKmUp); | |
177 | |
178 if (gaugeFinder == null) { | |
179 return false; | |
180 } | |
181 | |
182 loadFixings(session); | |
183 loadFixingsColumns(session); | |
184 loadFixingsColumnsKmRange(session); | |
185 | |
186 adjustExtent(); | |
187 | |
188 loadFixingsColumnsQRanges(session, gaugeFinder); | |
189 | |
190 return true; | |
191 } | |
192 | |
193 public static final Range FULL_EXTENT = new Range(-Double.MAX_VALUE, Double.MAX_VALUE); | |
194 | |
195 public static final FixingColumnFilter ACCEPT = new FixingColumnFilter() { | |
196 @Override | |
197 public boolean accept(final FixingColumn column) { | |
198 return true; | |
199 } | |
200 }; | |
201 | |
202 public static class NotFilter implements FixingColumnFilter { | |
203 protected FixingColumnFilter child; | |
204 | |
205 public NotFilter(final FixingColumnFilter child) { | |
206 this.child = child; | |
207 } | |
208 | |
209 @Override | |
210 public boolean accept(final FixingColumn column) { | |
211 return !this.child.accept(column); | |
212 } | |
213 } // class NotFilter | |
214 | |
215 public static abstract class ComponentFilter implements FixingColumnFilter { | |
216 protected List<FixingColumnFilter> children; | |
217 | |
218 public ComponentFilter() { | |
219 this.children = new ArrayList<>(); | |
220 } | |
221 | |
222 public ComponentFilter(final List<FixingColumnFilter> children) { | |
223 this.children = children; | |
224 } | |
225 | |
226 public ComponentFilter add(final FixingColumnFilter filter) { | |
227 this.children.add(filter); | |
228 return this; | |
229 } | |
230 } // class ComponentFilter | |
231 | |
232 public static class OrFilter extends ComponentFilter { | |
233 | |
234 public OrFilter() { | |
235 } | |
236 | |
237 public OrFilter(final List<FixingColumnFilter> children) { | |
238 super(children); | |
239 } | |
240 | |
241 @Override | |
242 public boolean accept(final FixingColumn column) { | |
243 for (final FixingColumnFilter child : this.children) { | |
244 if (child.accept(column)) { | |
245 return true; | |
246 } | |
247 } | |
248 return false; | |
249 } | |
250 } // class OrFilter | |
251 | |
252 public static class AndFilter extends ComponentFilter { | |
253 | |
254 public AndFilter() { | |
255 } | |
256 | |
257 public AndFilter(final List<FixingColumnFilter> children) { | |
258 super(children); | |
259 } | |
260 | |
261 @Override | |
262 public boolean accept(final FixingColumn column) { | |
263 for (final FixingColumnFilter child : this.children) { | |
264 if (!child.accept(column)) { | |
265 return false; | |
266 } | |
267 } | |
268 return true; | |
269 } | |
270 } // class AndFilter | |
271 | |
272 public static class IdFilter implements FixingColumnFilter { | |
273 | |
274 protected int columnId; | |
275 | |
276 public IdFilter(final int columnId) { | |
277 this.columnId = columnId; | |
278 } | |
279 | |
280 @Override | |
281 public boolean accept(final FixingColumn column) { | |
282 return column.getId() == this.columnId; | |
283 } | |
284 } // class IdFilter | |
285 | |
286 /** Accept Fixing columns whose id is in id list. */ | |
287 public static class IdsFilter implements FixingColumnFilter { | |
288 | |
289 protected int[] columnIds; | |
290 | |
291 public IdsFilter(final int[] columnIds) { | |
292 this.columnIds = columnIds; | |
293 } | |
294 | |
295 @Override | |
296 public boolean accept(final FixingColumn column) { | |
297 final int cid = column.getId(); | |
298 for (int i = this.columnIds.length - 1; i >= 0; --i) { | |
299 if (this.columnIds[i] == cid) { | |
300 return true; | |
301 } | |
302 } | |
303 return false; | |
304 } | |
305 } // class IdFilter | |
306 | |
307 public static class DateFilter implements FixingColumnFilter { | |
308 | |
309 protected Date date; | |
310 | |
311 public DateFilter(final Date date) { | |
312 this.date = date; | |
313 } | |
314 | |
315 @Override | |
316 public boolean accept(final FixingColumn column) { | |
317 return this.date.equals(column.getStartTime()); | |
318 } | |
319 } // class DateFilter | |
320 | |
321 public static class DateRangeFilter implements FixingColumnFilter { | |
322 | |
323 protected Date start; | |
324 protected Date end; | |
325 | |
326 public DateRangeFilter(final Date start, final Date end) { | |
327 if (start.before(end)) { | |
328 this.start = start; | |
329 this.end = end; | |
330 } else { | |
331 this.start = end; | |
332 this.end = start; | |
333 } | |
334 } | |
335 | |
336 @Override | |
337 public boolean accept(final FixingColumn column) { | |
338 final Date date = column.getStartTime(); | |
339 // start <= date <= end | |
340 return !(date.before(this.start) || date.after(this.end)); | |
341 } | |
342 } // class DateRangeFilter | |
343 | |
344 public static class SectorFilter implements FixingColumnFilter { | |
345 | |
346 protected int sector; | |
347 | |
348 public SectorFilter(final int sector) { | |
349 this.sector = sector; | |
350 } | |
351 | |
352 @Override | |
353 public boolean accept(final FixingColumn column) { | |
354 for (final SectorRange s : column.getSectors()) { | |
355 if (s.getSector() == this.sector) { | |
356 return true; | |
357 } | |
358 } | |
359 return false; | |
360 } | |
361 } // class SectorFilter | |
362 | |
363 public static class SectorRangeFilter implements FixingColumnFilter { | |
364 | |
365 protected int min; | |
366 protected int max; | |
367 | |
368 public SectorRangeFilter(final int min, final int max) { | |
369 this.min = Math.min(min, max); | |
370 this.max = Math.max(min, max); | |
371 } | |
372 | |
373 @Override | |
374 public boolean accept(final FixingColumn column) { | |
375 for (final SectorRange s : column.getSectors()) { | |
376 final int v = s.getSector(); | |
377 if (v < this.min || v > this.max) { | |
378 return false; | |
379 } | |
380 } | |
381 return true; | |
382 } | |
383 } // class SectorRangeFilter | |
384 | |
385 public static class KmFilter implements FixingColumnFilter { | |
386 | |
387 protected double km; | |
388 | |
389 public KmFilter(final double km) { | |
390 this.km = km; | |
391 } | |
392 | |
393 @Override | |
394 public boolean accept(final FixingColumn column) { | |
395 for (final SectorRange s : column.getSectors()) { | |
396 if (s.inside(this.km)) { | |
397 return true; | |
398 } | |
399 } | |
400 return false; | |
401 } | |
402 } // class KmFilter | |
403 | |
404 public void generateOverview(final Document document) { | |
405 generateOverview(document, FULL_EXTENT, ACCEPT); | |
406 } | |
407 | |
408 /** | |
409 * @param range | |
410 * can be null. | |
411 */ | |
412 public List<FixingColumn> filter(final Range range, final FixingColumnFilter filter) { | |
413 final List<FixingColumn> allColumns = new ArrayList<>(); | |
414 | |
415 for (final Fixing fixing : this.fixings) { | |
416 fixing.addAllColumns(allColumns, range, filter); | |
417 } | |
418 | |
419 Collections.sort(allColumns, Fixing.DATE_CMP); | |
420 | |
421 return allColumns; | |
422 } | |
423 | |
424 private static Range realRange(final List<FixingColumn> columns) { | |
425 Range range = null; | |
426 for (final FixingColumn column : columns) { | |
427 if (range == null) { | |
428 range = new Range(column); | |
429 } else { | |
430 range.extend(column); | |
431 } | |
432 } | |
433 return range; | |
434 } | |
435 | |
436 private Element intersectingGauges(final Document document, final Range range) { | |
437 final Element gauges = document.createElement("gauges"); | |
438 | |
439 if (range == null) { | |
440 return gauges; | |
441 } | |
442 | |
443 final GaugeFinderFactory gff = GaugeFinderFactory.getInstance(); | |
444 | |
445 final GaugeFinder gf = gff.getGaugeFinder(this.riverId, this.isKmUp); | |
446 | |
447 if (gf == null) { | |
448 return gauges; | |
449 } | |
450 | |
451 for (final GaugeRange gr : gf.getGauges()) { | |
452 if (gr.intersects(range)) { | |
453 final Element gauge = document.createElement("gauge"); | |
454 gauge.setAttribute("from", String.valueOf(gr.getStart())); | |
455 gauge.setAttribute("to", String.valueOf(gr.getEnd())); | |
456 gauge.setAttribute("name", gr.getName()); | |
457 gauges.appendChild(gauge); | |
458 } | |
459 } | |
460 | |
461 return gauges; | |
462 } | |
463 | |
464 /** Populate document with fixings, filtered by range and filter. */ | |
465 public void generateOverview(final Document document, final Range range, final FixingColumnFilter filter) { | |
466 final List<FixingColumn> allColumns = filter(range, filter); | |
467 | |
468 final Element fixingsElement = document.createElement("fixings"); | |
469 | |
470 final Element riverElement = document.createElement("river"); | |
471 | |
472 riverElement.setAttribute("from", String.valueOf(this.extent.getStart())); | |
473 riverElement.setAttribute("to", String.valueOf(this.extent.getEnd())); | |
474 riverElement.setAttribute("rid", String.valueOf(this.riverId)); | |
475 riverElement.setAttribute("name", this.riverName); | |
476 | |
477 fixingsElement.appendChild(riverElement); | |
478 | |
479 fixingsElement.appendChild(intersectingGauges(document, realRange(allColumns))); | |
480 | |
481 final SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); | |
482 | |
483 final Element esE = document.createElement("events"); | |
484 | |
485 for (final FixingColumn column : allColumns) { | |
486 | |
487 final List<SectorRange> sectors = column.getSectors(range); | |
488 | |
489 if (!sectors.isEmpty()) { | |
490 final Element eE = document.createElement("event"); | |
491 eE.setAttribute("description", String.valueOf(column.getDescription())); | |
492 eE.setAttribute("cid", String.valueOf(column.getId())); | |
493 eE.setAttribute("date", df.format(column.getStartTime())); | |
494 | |
495 for (final SectorRange sector : sectors) { | |
496 final Element sE = document.createElement("sector"); | |
497 | |
498 sE.setAttribute("from", String.valueOf(sector.getStart())); | |
499 sE.setAttribute("to", String.valueOf(sector.getEnd())); | |
500 sE.setAttribute("class", String.valueOf(sector.getSector())); | |
501 | |
502 eE.appendChild(sE); | |
503 } | |
504 | |
505 esE.appendChild(eE); | |
506 } | |
507 } | |
508 | |
509 fixingsElement.appendChild(esE); | |
510 | |
511 document.appendChild(fixingsElement); | |
512 } | |
513 | |
514 public Range getExtent() { | |
515 return this.extent; | |
516 } | |
517 } |