changeset 9409:38201f5b0dd9

Changed bundu bzws workflow to stop in case of missing daily discharge values and other minor changes
author mschaefer
date Thu, 16 Aug 2018 08:47:41 +0200
parents 66a43d9f65c8
children 52314c4ab3be
files artifacts/doc/conf/conf.xml artifacts/src/main/java/org/dive4elements/river/artifacts/services/DynamicMainValuesTimeRangeDeterminationService.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties backend/src/main/java/org/dive4elements/river/model/sinfo/DailyDischargeValue.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractWQAdaptedInputPanel.java gwt-client/src/main/java/org/dive4elements/river/client/server/AbstractMainValuesServiceImpl.java
diffstat 7 files changed, 101 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- 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</service-factory>
             <service-factory
+                name="dynamicMainvaluesTimeRangeDetermination"
+                service="org.dive4elements.river.artifacts.services.DynamicMainValuesTimeRangeDeterminationService"
+                description="Computes the available daily discharge time periods of the gauges of a river range">org.dive4elements.artifactdatabase.DefaultServiceFactory</service-factory>
+            <service-factory
                 name="metadata"
                 service="org.dive4elements.river.artifacts.services.MetaDataService"
                 description="The service provides some introspection into the database content.">org.dive4elements.artifactdatabase.DefaultServiceFactory</service-factory>
--- 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 <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
+ * 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<GaugeInfo> gaugeInfos;
 
-    private static class GaugeInfoResult {
-        private final String globalErrorMsg;
-        private final List<GaugeInfo> gaugeInfos;
-
-        private GaugeInfoResult(final List<GaugeInfo> gaugeInfos, final String globalErrorMsg) {
+        protected GaugeInfoResult(final List<GaugeInfo> 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<Gauge> gauges, final Date startTime, final Date endTime, final CallMeta meta)
             throws ServiceException {
 
         // Query the gauge's daily Q values
+        String globalErrorMsg = "";
         final List<GaugeInfoResult.GaugeInfo> 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<GaugeInfoResult.GaugeInfo> 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<Gauge> 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);
 
--- 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. 
--- 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. 
--- 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<Date> list = query.list();
-        if (list != null && list.size() == 1) {
-            return list.get(0);
+        query.setDate("startDate", fromDay);
+        query.setDate("endDate", toDay);
+        final List<Object[]> 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<Gauge, Date[]> fetchGaugesTimePeriod(final List<Gauge> gauges, final Date fromDay, final Date toDay) {
+        final Map<Gauge, Date[]> result = new TreeMap<>();
+        final Map<Integer, Gauge> 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<Object[]> 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<>();
+    }
 }
--- 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.
--- 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<WQInfoObject> WQ_INFO_OBJECT_CMP = new Comparator<WQInfoObject>() {
         @Override

http://dive4elements.wald.intevation.org