# HG changeset patch # User mschaefer # Date 1534402061 -7200 # Node ID 38201f5b0dd90db298580d09b2dd3c74e4d4ca2a # Parent 66a43d9f65c8ae8c15e4040264e839182f2b8c11 Changed bundu bzws workflow to stop in case of missing daily discharge values and other minor changes diff -r 66a43d9f65c8 -r 38201f5b0dd9 artifacts/doc/conf/conf.xml --- a/artifacts/doc/conf/conf.xml Thu Aug 16 08:44:26 2018 +0200 +++ b/artifacts/doc/conf/conf.xml Thu Aug 16 08:47:41 2018 +0200 @@ -232,6 +232,10 @@ service="org.dive4elements.river.artifacts.services.DynamicMainValuesService" description="Computes the main values of a river's gauge based on a start and end point of the river, long-time discharge values and a time period">org.dive4elements.artifactdatabase.DefaultServiceFactory org.dive4elements.artifactdatabase.DefaultServiceFactory + org.dive4elements.artifactdatabase.DefaultServiceFactory diff -r 66a43d9f65c8 -r 38201f5b0dd9 artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesTimeRangeDeterminationService.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesTimeRangeDeterminationService.java Thu Aug 16 08:44:26 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesTimeRangeDeterminationService.java Thu Aug 16 08:47:41 2018 +0200 @@ -25,16 +25,12 @@ import org.dive4elements.river.model.Gauge; import org.dive4elements.river.model.River; import org.dive4elements.river.model.sinfo.DailyDischargeValue; -import org.dive4elements.river.model.sinfo.DailyDischargeValue.MinMax; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** - * This service returns the main values of a river's gauge based on the start - * and end point of the river. - * - * @author Ingo Weinzierl + * This service returns the list of gauges with daily discharge time periods and error messages */ public class DynamicMainValuesTimeRangeDeterminationService extends D4EService { @@ -53,26 +49,20 @@ } } - /** - * Computes a gauge's main values for a period of time based on its daily discharges stored in the database - * - * @throws Exception - */ + private static class GaugeInfoResult { + protected final String globalErrorMsg; + protected final List gaugeInfos; - private static class GaugeInfoResult { - private final String globalErrorMsg; - private final List gaugeInfos; - - private GaugeInfoResult(final List gaugeInfos, final String globalErrorMsg) { + protected GaugeInfoResult(final List gaugeInfos, final String globalErrorMsg) { this.gaugeInfos = gaugeInfos; this.globalErrorMsg = globalErrorMsg; } private static class GaugeInfo { - private final String errorMsg; - private final Gauge gauge; - private final Date startdate; - private final Date enddate; + protected final String errorMsg; + protected final Gauge gauge; + protected final Date startdate; + protected final Date enddate; public GaugeInfo(final String errorMsg, final Gauge gauge, final Date startdate, final Date enddate) { this.errorMsg = errorMsg; @@ -83,35 +73,41 @@ } } + /** + * Queries the available daily discharge time periods of a list of gauges from the database and checks the overlapping + * + * @throws ServiceException + */ private GaugeInfoResult getCommonTimeRangeForGauges(final List gauges, final Date startTime, final Date endTime, final CallMeta meta) throws ServiceException { // Query the gauge's daily Q values + String globalErrorMsg = ""; final List gaugeResults = new ArrayList<>(); Date min = startTime; Date max = endTime; for (final Gauge gauge : gauges) { - final Date minGlobalForGauge = DailyDischargeValue.getGlobalMinMax(gauge, MinMax.min); - final Date maxGlobalForGauge = DailyDischargeValue.getGlobalMinMax(gauge, MinMax.max); - if (minGlobalForGauge == null || maxGlobalForGauge == null) { // der Fall, dass nur eins von beiden null ist, kann eigentlich nciht vorkommen - gaugeResults.add(new GaugeInfoResult.GaugeInfo(getMsg(meta, "bundu.wst_no_data_at_all"), gauge, null, null)); - // TODO : wenn der Workflow abgebrochen werden soll, GlobalErrorMsg setzen, dass mind. ein Pegel überhaupt keine Daten - // hat (der Mechnismus auf Client-Seite ist schon implementiert) - + final Date[] gaugeDates = DailyDischargeValue.getTimePeriod(gauge, startTime, endTime); + if (gaugeDates[0] == null) { + final String msg = Resources.getMsg(meta, "bundu.wst_no_data_at_all", "bundu.wst_no_data_at_all", gauge.getName()); + final GaugeInfoResult.GaugeInfo gi = new GaugeInfoResult.GaugeInfo(msg, gauge, null, null); + gaugeResults.add(gi); + if (globalErrorMsg.isEmpty()) + globalErrorMsg = msg; continue; } - if (minGlobalForGauge.getTime() > startTime.getTime()) - min = minGlobalForGauge; + if (gaugeDates[0].getTime() > startTime.getTime()) + min = gaugeDates[0]; - if (maxGlobalForGauge.getTime() < endTime.getTime()) - max = maxGlobalForGauge; + if (gaugeDates[1].getTime() < endTime.getTime()) + max = gaugeDates[1]; String errormsg = null; - if ((maxGlobalForGauge.getTime() < endTime.getTime()) || (minGlobalForGauge.getTime() > startTime.getTime())) - errormsg = makeDoesNotCoverErrorMsg(minGlobalForGauge, maxGlobalForGauge, meta); + if ((gaugeDates[1].getTime() < endTime.getTime()) || (gaugeDates[0].getTime() > startTime.getTime())) + errormsg = makeDoesNotCoverErrorMsg(gaugeDates[0], gaugeDates[1], meta); gaugeResults.add(new GaugeInfoResult.GaugeInfo(errormsg, gauge, min, max)); } @@ -119,10 +115,11 @@ // common Range and correct errorMsg final List gaugeResultsSecondTurn = new ArrayList<>(); for (final GaugeInfoResult.GaugeInfo gi : gaugeResults) { - gaugeResultsSecondTurn - .add(new GaugeInfoResult.GaugeInfo(gi.errorMsg, gi.gauge, gi.startdate != null ? min : null, gi.enddate != null ? max : null)); + gaugeResultsSecondTurn.add(new GaugeInfoResult.GaugeInfo(gi.errorMsg, gi.gauge, gi.startdate != null ? min : null, + gi.enddate != null ? max : null)); } - final String globalErrorMsg = (min.getTime() > max.getTime()) ? getMsg(meta, "bundu.wst.gauge_timeranges_disjoint") : ""; + if (globalErrorMsg.isEmpty() && (min.getTime() > max.getTime())) + globalErrorMsg = getMsg(meta, "bundu.wst.gauge_timeranges_disjoint"); final GaugeInfoResult result = new GaugeInfoResult(gaugeResultsSecondTurn, globalErrorMsg); return result; @@ -140,10 +137,10 @@ @Override public Document doProcess(final Document data, final GlobalContext context, final CallMeta callMeta) { try { - final River river = AbstractMainValuesService.getRequestedRiver(data, "/art:" + this.ROOT_NODE + "/art:river/text()"); + final River river = AbstractMainValuesService.getRequestedRiver(data, "/art:" + ROOT_NODE + "/art:river/text()"); final List gauges = getRequestedGauges(data, river, callMeta); - final Date start = getRequestedStartYear(data, "/art:" + this.ROOT_NODE + "/art:startYear/text()"); - final Date end = getRequestedEndYear(data, "/art:" + this.ROOT_NODE + "/art:endYear/text()"); + final Date start = getRequestedStartYear(data, "/art:" + ROOT_NODE + "/art:startYear/text()"); + final Date end = getRequestedEndYear(data, "/art:" + ROOT_NODE + "/art:endYear/text()"); final GaugeInfoResult result = getCommonTimeRangeForGauges(gauges, start, end, callMeta); diff -r 66a43d9f65c8 -r 38201f5b0dd9 artifacts/src/main/resources/messages.properties --- a/artifacts/src/main/resources/messages.properties Thu Aug 16 08:44:26 2018 +0200 +++ b/artifacts/src/main/resources/messages.properties Thu Aug 16 08:47:41 2018 +0200 @@ -1294,7 +1294,7 @@ bundu.wst.export.csv.meta.header.bezugswst = Bezugswasserstand bundu.wst.export.pdf.meta.header.bezugswst = Bezugs-wasserstand -bundu.wst_no_data_at_all = Es liegt keine Abflussganglinie vor. +bundu.wst_no_data_at_all = Es liegt keine Abflussganglinie vor ({0}) bundu.wst.range_does_not_cover = Die Abflussganglinie ({0}-{1}) deckt nicht den Bezugszeitraum ab. bundu.wst.error_reading_gauges = Fehler beim Abruf des Pegels aus der Datenbank. bundu.wst.gauge_timeranges_disjoint = Der Bezugszeitraum konnte nicht auf die vorhandenen Abflusswerte eingeschr\u00e4nkt werden. diff -r 66a43d9f65c8 -r 38201f5b0dd9 artifacts/src/main/resources/messages_de.properties --- a/artifacts/src/main/resources/messages_de.properties Thu Aug 16 08:44:26 2018 +0200 +++ b/artifacts/src/main/resources/messages_de.properties Thu Aug 16 08:47:41 2018 +0200 @@ -1294,7 +1294,7 @@ bundu.wst.export.csv.meta.header.bezugswst = Bezugswasserstand bundu.wst.export.pdf.meta.header.bezugswst = Bezugs-wasserstand -bundu.wst_no_data_at_all = Es liegt keine Abflussganglinie vor. +bundu.wst_no_data_at_all = Es liegt keine Abflussganglinie vor ({0}) bundu.wst.range_does_not_cover = Die Abflussganglinie ({0}-{1}) deckt nicht den Bezugszeitraum ab. bundu.wst.error_reading_gauges = Fehler beim Abruf des Pegels aus der Datenbank. bundu.wst.gauge_timeranges_disjoint = Der Bezugszeitraum konnte nicht auf die vorhandenen Abflusswerte eingeschr\u00e4nkt werden. diff -r 66a43d9f65c8 -r 38201f5b0dd9 backend/src/main/java/org/dive4elements/river/model/sinfo/DailyDischargeValue.java --- a/backend/src/main/java/org/dive4elements/river/model/sinfo/DailyDischargeValue.java Thu Aug 16 08:44:26 2018 +0200 +++ b/backend/src/main/java/org/dive4elements/river/model/sinfo/DailyDischargeValue.java Thu Aug 16 08:47:41 2018 +0200 @@ -13,6 +13,8 @@ import java.io.Serializable; import java.util.Date; import java.util.List; +import java.util.Map; +import java.util.TreeMap; import javax.persistence.Column; import javax.persistence.Entity; @@ -27,7 +29,9 @@ import org.dive4elements.river.backend.SessionHolder; import org.dive4elements.river.model.Gauge; import org.hibernate.Query; +import org.hibernate.SQLQuery; import org.hibernate.Session; +import org.hibernate.type.StandardBasicTypes; /** * Hibernate binding for the DB table daily_discharge_values @@ -49,9 +53,6 @@ DAY, DISCHARGE; } - public enum MinMax { - min, max - } /***** FIELDS *****/ @@ -65,6 +66,7 @@ private Double discharge; + /***** CONSTRUCTORS *****/ public DailyDischargeValue() { @@ -83,6 +85,7 @@ this(dailyDischarge, day, Double.valueOf(discharge)); } + /***** METHODS *****/ @Id @@ -142,17 +145,62 @@ /** * Selects from the database the daily discharge, puts the first and the last into a List (min, max day) */ - - public static Date getGlobalMinMax(final Gauge gauge, final MinMax minmax) { + public static Date[] getTimePeriod(final Gauge gauge, final Date fromDay, final Date toDay) { final Session session = SessionHolder.HOLDER.get(); - final Query query = session.createQuery( - "SELECT " + minmax.toString() + "(v.day) " + " FROM DailyDischargeValue AS v JOIN v.dailyDischarge AS s" + " WHERE (s.gauge.id=:gaugeid)"); + final Query query = session.createQuery("SELECT MIN(v.day), MAX(v.day)" + + " FROM DailyDischargeValue AS v JOIN v.dailyDischarge AS s" + + " WHERE (s.gauge.id=:gaugeid) AND (v.day BETWEEN :startDate AND :endDate)"); query.setParameter("gaugeid", gauge.getId()); - final List list = query.list(); - if (list != null && list.size() == 1) { - return list.get(0); + query.setDate("startDate", fromDay); + query.setDate("endDate", toDay); + final List list = query.list(); + if (!list.isEmpty()) { + return new Date[] { (Date) list.get(0)[0], (Date) list.get(0)[1] }; } return null; } + /** + * Fetches a map of minimum+maximum daily discharge dates (or null) by gauge for a list of gauges and a time period + */ + public static Map fetchGaugesTimePeriod(final List gauges, final Date fromDay, final Date toDay) { + final Map result = new TreeMap<>(); + final Map gaugelookup = new TreeMap<>(); + String gaugeids = ""; + String sep = ""; + for (final Gauge gauge : gauges) { + gaugeids += sep + gauge.getId().toString(); + sep = ","; + result.put(gauge, null); + gaugelookup.put(gauge.getId(), gauge); + } + final Session session = SessionHolder.HOLDER.get(); + final SQLQuery query = session.createSQLQuery("SELECT g.id AS gauge_id, MIN(v.day) AS min_day, MAX(v.day) AS max_day" + + "FROM (gauges g LEFT JOIN daily_discharge s ON g.id=s.gauge_id)" + + " LEFT JOIN daily_discharge_values v ON s.id=v.daily_discharge_id" + + " WHERE g.id IN (:gaugeids)" + + " AND v.day BETWEEN :fromDay AND :toDay" + + " GROUP BY g.id" + + "UNION SELECT id, NULL, NULL" + + " FROM gauges" + + " WHERE id IN (:gaugeids)" + + " AND id NOT IN " + +" (SELECT s2.gauge_id FROM daily_discharge s2 INNER JOIN daily_discharge_values v2 ON s2.id=v2.daily_discharge_id" + + " WHERE v2.day BETWEEN :fromDay AND :toDay)" + + "ORDER BY 1") + .addScalar("gauge_id", StandardBasicTypes.INTEGER) + .addScalar("min_day", StandardBasicTypes.DATE) + .addScalar("max_day", StandardBasicTypes.DATE); + query.setString("gaugeids", gaugeids); + query.setDate("fromDay", fromDay); + query.setDate("toDay", toDay); + final List rows = query.list(); + if (!rows.isEmpty()) { + // TODO handle nulls + for (int i = 0; i <= rows.size() - 1; i++) + result.put(gaugelookup.get(rows.get(i)[0]), new Date[] { (Date) rows.get(i)[1], (Date) rows.get(i)[2] }); + return result; + } + return new TreeMap<>(); + } } diff -r 66a43d9f65c8 -r 38201f5b0dd9 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java Thu Aug 16 08:44:26 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java Thu Aug 16 08:47:41 2018 +0200 @@ -115,7 +115,7 @@ final String msg = this.getWQInfoMsg(); final Label test = PanelHelper.getValidationLabel(); test.setText(msg); - test.getElement().getStyle().setColor("red"); + test.getElement().getStyle().setColor("black"); test.getElement().getStyle().setPadding(1, Unit.MM); // For each gauge, add two tabs with helper tables. diff -r 66a43d9f65c8 -r 38201f5b0dd9 gwt-client/src/main/java/org/dive4elements/river/client/server/AbstractMainValuesServiceImpl.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/AbstractMainValuesServiceImpl.java Thu Aug 16 08:44:26 2018 +0200 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/AbstractMainValuesServiceImpl.java Thu Aug 16 08:47:41 2018 +0200 @@ -37,7 +37,7 @@ */ abstract class AbstractMainValuesServiceImpl extends RemoteServiceServlet { - private static final Logger log = Logger.getLogger(DynamicMainValuesServiceImpl.class); + private static final Logger log = Logger.getLogger(AbstractMainValuesServiceImpl.class); private static final Comparator WQ_INFO_OBJECT_CMP = new Comparator() { @Override