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 }

http://dive4elements.wald.intevation.org