changeset 9614:d889ffe2fb05

Nachtrag Pos. 20: rename type/part to group/type, group added in Infrastructure class
author mschaefer
date Wed, 09 Oct 2019 19:17:06 +0200
parents f8308db94634
children ca492336570b
files artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultType.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FacetCalculator.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties backend/doc/schema/oracle-sinfo-uinfo.sql backend/doc/schema/postgresql-sinfo-uinfo.sql backend/src/main/java/org/dive4elements/river/model/sinfo/Infrastructure.java backend/src/main/java/org/dive4elements/river/model/sinfo/InfrastructureValue.java
diffstat 12 files changed, 121 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultType.java	Wed Oct 09 16:17:16 2019 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/SInfoResultType.java	Wed Oct 09 19:17:06 2019 +0200
@@ -117,6 +117,21 @@
     };
 
     // TODO: check, if it is being used correctly
+    public static final SInfoResultType infrastructuregroup = new SInfoResultType(I18NStrings.UNIT_NONE,
+            "sinfo.export.flood_duration.csv.header.infrastructure_group", "sinfo.export.flood_duration.pdf.header.infrastructure_group") {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public String exportValue(final CallContext context, final Object value) {
+            return exportStringValue(value);
+        }
+
+        @Override
+        protected NumberFormat createFormatter(final CallContext context) {
+            throw new UnsupportedOperationException();
+        }
+    };
+    //
     public static final SInfoResultType infrastructuretype = new SInfoResultType(I18NStrings.UNIT_NONE,
             "sinfo.export.flood_duration.csv.header.infrastructure_type", "sinfo.export.flood_duration.pdf.header.infrastructure_type") {
         private static final long serialVersionUID = 1L;
@@ -131,21 +146,13 @@
             throw new UnsupportedOperationException();
         }
     };
-    //
-    public static final SInfoResultType infrastructurepart = new SInfoResultType(I18NStrings.UNIT_NONE,
-            "sinfo.export.flood_duration.csv.header.infrastructure_part", "sinfo.export.flood_duration.pdf.header.infrastructure_part") {
-        private static final long serialVersionUID = 1L;
 
-        @Override
-        public String exportValue(final CallContext context, final Object value) {
-            return exportStringValue(value);
-        }
-
-        @Override
-        protected NumberFormat createFormatter(final CallContext context) {
-            throw new UnsupportedOperationException();
-        }
-    };
+    /**
+     * Gets the label of the type and bank location of an infrastructure
+     */
+    public static final String getInfrastructureLabel(final CallContext context, final String group, final String type, final AttributeKey riverside) {
+        return group + " - " + type + " (" + localizeRiverside(context, riverside) + ")";
+    }
 
     public static final SInfoResultType dischargeLong = new SInfoResultType(I18NStrings.UNIT_CUBIC_M, "sinfo.export.collision.csv.header.discharge_long") {
         private static final long serialVersionUID = 1L;
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FacetCalculator.java	Wed Oct 09 16:17:16 2019 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FacetCalculator.java	Wed Oct 09 19:17:06 2019 +0200
@@ -112,10 +112,7 @@
      */
     private StickyAxisAnnotation calcInfrastructureQAnnotation(final ResultRow row) {
         final String label = Resources.getMsg(this.m_context.getMeta(), "sinfo.chart.flood_duration.curve.infrastructure",
-                "sinfo.chart.flood_duration.curve.infrastructure",
-                SInfoResultType.infrastructuretype.exportValue(this.m_context, row.getValue(SInfoResultType.infrastructuretype)) + " - "
-                        + SInfoResultType.infrastructurepart.exportValue(this.m_context, row.getValue(SInfoResultType.infrastructurepart)) + " ("
-                        + SInfoResultType.riverside.exportValue(this.m_context, row.getValue(SInfoResultType.riverside)) + ")");
+                "sinfo.chart.flood_duration.curve.infrastructure", getInfrastructureLabel(row));
         final StickyAxisAnnotation annotation = new StickyAxisAnnotation(label, (float) row.getDoubleValue(SInfoResultType.floodDischarge), SimpleAxis.Y_AXIS,
                 FloodDurationCurveGenerator.YAXIS.Q.idx);
         annotation.setHitPoint((float) row.getDoubleValue(SInfoResultType.floodDuration));
@@ -127,10 +124,7 @@
      */
     private StickyAxisAnnotation calcInfrastructureWAnnotation(final ResultRow row) {
         final String label = Resources.getMsg(this.m_context.getMeta(), "sinfo.chart.flood_duration.curve.infrastructure",
-                "sinfo.chart.flood_duration.curve.infrastructure",
-                SInfoResultType.infrastructuretype.exportValue(this.m_context, row.getValue(SInfoResultType.infrastructuretype)) + " - "
-                        + SInfoResultType.infrastructurepart.exportValue(this.m_context, row.getValue(SInfoResultType.infrastructurepart)) + " ("
-                        + SInfoResultType.riverside.exportValue(this.m_context, row.getValue(SInfoResultType.riverside)) + ")");
+                "sinfo.chart.flood_duration.curve.infrastructure", getInfrastructureLabel(row));
         final StickyAxisAnnotation annotation = new StickyAxisAnnotation(label, (float) row.getDoubleValue(SInfoResultType.infrastructureHeight),
                 SimpleAxis.Y_AXIS, FloodDurationCurveGenerator.YAXIS.W.idx);
         annotation.setHitPoint((float) row.getDoubleValue(SInfoResultType.floodDuration));
@@ -138,6 +132,14 @@
     }
 
     /**
+     * Builds the label of the type and bank location of the infrastructure of a result row
+     */
+    private String getInfrastructureLabel(final ResultRow row) {
+        return SInfoResultType.getInfrastructureLabel(this.m_context, (String) row.getValue(SInfoResultType.infrastructuregroup),
+                (String) row.getValue(SInfoResultType.infrastructuretype), (AttributeKey) row.getValue(SInfoResultType.riverside));
+    }
+
+    /**
      * Searches the one or two rows of a station in a result rows collection
      *
      * @param m_riverside
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java	Wed Oct 09 16:17:16 2019 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculation.java	Wed Oct 09 19:17:06 2019 +0200
@@ -76,7 +76,7 @@
 
         final FloodDurationCalculator calculator = new FloodDurationCalculator(this.context, riverInfoProvider);
 
-        // FIXME: fetch from acces; maybe we need database for that... whatever
+        // FIXME: fetch from access; maybe we need database for that... whatever
         final Set<Infrastructure> infrastructureKeys = null;
 
         calculator.execute(problems, label, calcRange, access.getRiverside(), infrastructureKeys, access.getIsWspl(), winfo, results);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java	Wed Oct 09 16:17:16 2019 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculationResult.java	Wed Oct 09 19:17:06 2019 +0200
@@ -74,10 +74,10 @@
 
         private static final long serialVersionUID = 1L;
 
+        private final String m_group;
+
         private final String m_type;
 
-        private final String m_part;
-
         private final AttributeKey m_riverside;
 
         private static final String FACET_FLOOD_DURATION_DESCRIPTION = "sinfo_facet_flood_duration";
@@ -85,8 +85,8 @@
         private static final String FACET_ABSOLUTE_HEIGHT = "sinfo.flood_duration.absolute.height";
 
         public Infrastructure(final ResultRow row) {
+            this.m_group = String.valueOf(row.getValue(SInfoResultType.infrastructuregroup));
             this.m_type = String.valueOf(row.getValue(SInfoResultType.infrastructuretype));
-            this.m_part = String.valueOf(row.getValue(SInfoResultType.infrastructurepart));
             final String riversideStr = String.valueOf(row.getValue(SInfoResultType.riverside));
             this.m_riverside = riversideStr.equals("null") ? AttributeKey.NONE : AttributeKey.valueOf(riversideStr);
         }
@@ -98,8 +98,8 @@
         @Override
         public int hashCode() {
             return new HashCodeBuilder() //
+                    .append(this.m_group)//
                     .append(this.m_type)//
-                    .append(this.m_part)//
                     .append(this.m_riverside)//
                     .toHashCode();
         }
@@ -116,24 +116,20 @@
 
             final Infrastructure other = (Infrastructure) obj;
             return new EqualsBuilder() //
+                    .append(this.m_group, other.m_group) //
                     .append(this.m_type, other.m_type) //
-                    .append(this.m_part, other.m_part) //
                     .append(this.m_riverside, other.m_riverside) //
                     .isEquals();
         }
 
         public String getFloodHeightLabel(final CallContext context) {
-            return Resources.getMsg(context.getMeta(), FACET_ABSOLUTE_HEIGHT, FACET_ABSOLUTE_HEIGHT) + " " + this.m_type + " - " + this.m_part + " ("
-                    + getLocalizedRiverside(context) + ")";
+            return Resources.getMsg(context.getMeta(), FACET_ABSOLUTE_HEIGHT, FACET_ABSOLUTE_HEIGHT)
+                    + " " + SInfoResultType.getInfrastructureLabel(context, this.m_group, this.m_type, this.m_riverside);
         }
 
         public String getFloodDurationLabel(final CallContext context) {
-            return Resources.getMsg(context.getMeta(), FACET_FLOOD_DURATION_DESCRIPTION, FACET_FLOOD_DURATION_DESCRIPTION) + " " + this.m_type + " - "
-                    + this.m_part + " (" + getLocalizedRiverside(context) + ")";
-        }
-
-        private String getLocalizedRiverside(final CallContext callContext) {
-            return SInfoResultType.localizeRiverside(callContext, this.m_riverside);
+            return Resources.getMsg(context.getMeta(), FACET_FLOOD_DURATION_DESCRIPTION, FACET_FLOOD_DURATION_DESCRIPTION)
+                    + " " + SInfoResultType.getInfrastructureLabel(context, this.m_group, this.m_type, this.m_riverside);
         }
     }
 
@@ -145,7 +141,7 @@
 
     private final int maxWaterlevelPdf = 3;
 
-    private final Set<Infrastructure> m_infastructures;
+    private final Set<Infrastructure> m_infrastructures;
 
     public interface ValueGetter {
         double getValue(DurationWaterlevel waterlevel);
@@ -160,11 +156,11 @@
         super(label, rows);
         this.waterlevelLabels = mainvalueLabels;
         this.isUseWspl = isUseWspl;
-        this.m_infastructures = infrastructures;
+        this.m_infrastructures = infrastructures;
     }
 
-    public Set<Infrastructure> getInfastructureMap() {
-        return this.m_infastructures;
+    public Set<Infrastructure> getInfrastructureMap() {
+        return this.m_infrastructures;
     }
 
     /**
@@ -178,7 +174,7 @@
 
         final List<ResultRow> infrasOnlyRows = new ArrayList<>();
         for (final ResultRow row : rows) {
-            if (row.getValue(SInfoResultType.infrastructuretype) != null && row.getValue(SInfoResultType.infrastructurepart) != null)
+            if (row.getValue(SInfoResultType.infrastructuregroup) != null && row.getValue(SInfoResultType.infrastructuretype) != null)
                 infrasOnlyRows.add(row);
         }
         return Collections.unmodifiableCollection(infrasOnlyRows);
@@ -216,8 +212,8 @@
         lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.floodDischarge));
 
         lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructureHeight));
+        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructuregroup));
         lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructuretype));
-        lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructurepart));
 
         final List<DurationWaterlevel> waterlevelList = (List<DurationWaterlevel>) row.getValue(SInfoResultType.customMultiRowColWaterlevel);
 
@@ -262,8 +258,8 @@
         header.add(exportContextCSV.formatCsvHeader(SInfoResultType.floodDuration));
         header.add(exportContextCSV.msgUnitCSV(SInfoResultType.floodDischarge, SInfoResultType.floodDischarge.getUnit()));
         header.add(exportContextCSV.msgUnitCSV(SInfoResultType.infrastructureHeight, river.getWstUnit()));
+        header.add(exportContextCSV.formatCsvHeader(SInfoResultType.infrastructuregroup));
         header.add(exportContextCSV.formatCsvHeader(SInfoResultType.infrastructuretype));
-        header.add(exportContextCSV.formatCsvHeader(SInfoResultType.infrastructurepart));
 
         // add dynamic headers
         final int waterlevelCount = // results.
@@ -312,8 +308,9 @@
         exportContextPDF.addJRMetadata(source, "inundationduration_header", SInfoResultType.floodDuration);
         exportContextPDF.addJRMetadata(source, "inundationduration_q_header", SInfoResultType.floodDischarge);
         exportContextPDF.addJRMetadata(source, "infrastructure_height_header", SInfoResultType.infrastructureHeight);
-        exportContextPDF.addJRMetadata(source, "infrastructure_type_header", SInfoResultType.infrastructuretype);
-        exportContextPDF.addJRMetadata(source, "infrastructure_part_header", SInfoResultType.infrastructurepart);
+        // FIXME Tironi: report-keys ..type => ..group und ..part => ..type umbenennen zwecks Einheitlichkeit
+        exportContextPDF.addJRMetadata(source, "infrastructure_type_header", SInfoResultType.infrastructuregroup);
+        exportContextPDF.addJRMetadata(source, "infrastructure_part_header", SInfoResultType.infrastructuretype);
 
         for (int i = 1; i <= this.getWaterlevelCount(); i++) {
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java	Wed Oct 09 16:17:16 2019 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationCalculator.java	Wed Oct 09 19:17:06 2019 +0200
@@ -286,8 +286,8 @@
 
         final ResultRow row = ResultRow.create();
         row.putValue(GeneralResultType.station, station);
-        row.putValue(SInfoResultType.infrastructuretype, null); // is replaced later for an infrastructure type
-        row.putValue(SInfoResultType.infrastructurepart, null); // is replaced later for an infrastructure part
+        row.putValue(SInfoResultType.infrastructuregroup, null); // is replaced later for an infrastructure type
+        row.putValue(SInfoResultType.infrastructuretype, null); // is replaced later for an infrastructure part
         row.putValue(SInfoResultType.floodDuration, Double.NaN); // is replaced later for an infrastructure
 
         final String gaugeLabel = this.riverInfoProvider2.findGauge(station);
@@ -310,8 +310,6 @@
 
     /**
      * Calculate the result row fields for one infrastructure
-     *
-     * @param map
      */
     private void calculateInfrastructure(final ResultRow row, final Gauge gauge, final InfrastructureValue infrastructure, final WstValueTable wst,
             final Map<Gauge, GaugeDurationValuesFinder> durFinders, final Set<Infrastructure> infrastructures) {
@@ -325,13 +323,9 @@
         row.putValue(SInfoResultType.riverside, infrastructure.getAttributeKey());
         row.putValue(SInfoResultType.floodDischarge, q);
         row.putValue(SInfoResultType.infrastructureHeight, infrastructure.getHeight());
+        row.putValue(SInfoResultType.infrastructuregroup, infrastructure.getInfrastructure().getGroup().getName());
         row.putValue(SInfoResultType.infrastructuretype, infrastructure.getInfrastructure().getType().getName());
 
-        int dochNichtRandom = (int) (q / 20 + 1);
-        if (dochNichtRandom > 10)
-            dochNichtRandom = 4;
-
-        row.putValue(SInfoResultType.infrastructurepart, "TEST_" + dochNichtRandom);
         // Determine the relative column position of the Q of the infrastructure height
         final QPosition qPos = wst.getQPosition(infrastructure.getStation().doubleValue(), q);
         if (qPos == null)
@@ -343,8 +337,8 @@
         // Set D in the result row
         row.putValue(SInfoResultType.floodDuration, dur);
 
-        final FloodDurationCalculationResult.Infrastructure typePart = new FloodDurationCalculationResult.Infrastructure(row);
-        infrastructures.add(typePart);
+        final FloodDurationCalculationResult.Infrastructure groupType = new FloodDurationCalculationResult.Infrastructure(row);
+        infrastructures.add(groupType);
     }
 
     /**
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Wed Oct 09 16:17:16 2019 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flood_duration/FloodDurationState.java	Wed Oct 09 19:17:06 2019 +0200
@@ -128,7 +128,7 @@
                 facets.add(FloodDurationCurveProcessor.createInfrastructureFacet(context, hash, this.id, result, themeCount++, resultIndex, false, riversideC));
             }
 
-            final Set<Infrastructure> infrastructures = result.getInfastructureMap();
+            final Set<Infrastructure> infrastructures = result.getInfrastructureMap();
             for (final Infrastructure entry : infrastructures) {
 
                 facets.add(FloodDurationProcessor.createFloodDurationFacet(context, hash, this.id, result, themeCount++, resultIndex, entry));
--- a/artifacts/src/main/resources/messages.properties	Wed Oct 09 16:17:16 2019 +0200
+++ b/artifacts/src/main/resources/messages.properties	Wed Oct 09 19:17:06 2019 +0200
@@ -976,12 +976,12 @@
 sinfo.export.flood_duration.csv.header.infrastructure.height = Infrastructure Height
 sinfo.export.flood_duration.csv.header.duration = Flooding Duration [d/a]
 sinfo.export.flood_duration.csv.header.discharge = Flooding Duration Discharge Q
-sinfo.export.flood_duration.csv.header.infrastructure_type = Infrastructure
-sinfo.export.flood_duration.csv.header.infrastructure_part = Type/Designation
-sinfo.export.flood_duration.pdf.header.infrastructure_part = Type/ Designa-tion
+sinfo.export.flood_duration.csv.header.infrastructure_group = Infrastructure
+sinfo.export.flood_duration.csv.header.infrastructure_type = Type/Name
+sinfo.export.flood_duration.pdf.header.infrastructure_type = Type/ Name
 sinfo.export.flood_duration.pdf.header.duration = Flooding Duration Discharge [d/a]
 sinfo.export.flood_duration.pdf.header.discharge = Flooding Duration Discharge Q [m\u00b3/s]
-sinfo.export.flood_duration.pdf.header.infrastructure_type = Infrastruc-ture
+sinfo.export.flood_duration.pdf.header.infrastructure_group = Infrastruc-ture
 sinfo.export.flood_duration.pdf.header.infrastructure.height =  Infrastruc-ture Height
 
 sinfo.chart.flow_depth.section.title=h-Longitudinal Section
--- a/artifacts/src/main/resources/messages_de.properties	Wed Oct 09 16:17:16 2019 +0200
+++ b/artifacts/src/main/resources/messages_de.properties	Wed Oct 09 19:17:06 2019 +0200
@@ -976,12 +976,12 @@
 sinfo.export.flood_duration.csv.header.infrastructure.height = H\u00f6he der Infrastruktur
 sinfo.export.flood_duration.csv.header.duration = \u00dcberflutungsdauer [d/a]
 sinfo.export.flood_duration.csv.header.discharge = \u00dcberflutungsdauerabfluss Q
-sinfo.export.flood_duration.csv.header.infrastructure_type = Infrastruktur
-sinfo.export.flood_duration.csv.header.infrastructure_part = Typ/Bezeichnung
-sinfo.export.flood_duration.pdf.header.infrastructure_part = Typ/ Bezeich-nung
+sinfo.export.flood_duration.csv.header.infrastructure_group = Infrastruktur
+sinfo.export.flood_duration.csv.header.infrastructure_type = Typ/Bezeichnung
+sinfo.export.flood_duration.pdf.header.infrastructure_type = Typ/ Bezeich-nung
 sinfo.export.flood_duration.pdf.header.duration = \u00dcber-flutungs-dauer [d/a]
 sinfo.export.flood_duration.pdf.header.discharge = \u00dcber-flutungs-dauer-abfluss Q [m\u00b3/s]
-sinfo.export.flood_duration.pdf.header.infrastructure_type = Infra-struktur-typ
+sinfo.export.flood_duration.pdf.header.infrastructure_group = Infra-struktur
 sinfo.export.flood_duration.pdf.header.infrastructure.height = H\u00f6he der Infra-struktur
 
 sinfo.chart.flow_depth.section.title=h-L\u00e4ngsschnitt
--- a/backend/doc/schema/oracle-sinfo-uinfo.sql	Wed Oct 09 16:17:16 2019 +0200
+++ b/backend/doc/schema/oracle-sinfo-uinfo.sql	Wed Oct 09 19:17:06 2019 +0200
@@ -85,6 +85,7 @@
     id  NUMBER(9,0) PRIMARY KEY,
     river_id  NUMBER(38,0) NOT NULL CONSTRAINT cInfrastructureRivers REFERENCES rivers(id) ON DELETE CASCADE,
     annotation_type_id  NUMBER(38,0) NOT NULL CONSTRAINT cInfrastructureAnnotationType REFERENCES annotation_types(id),
+    group_id  NUMBER(38,0) NOT NULL CONSTRAINT cInfrastructureGroupAnnoType REFERENCES annotation_types(id),
     year  NUMBER(4,0) CHECK((year >= 1700) AND (year <= 2199)),
     dataprovider  VARCHAR2(256),
     evaluation_by  VARCHAR2(256),
@@ -93,6 +94,7 @@
     notes  VARCHAR2(256)
 );
 COMMENT ON TABLE infrastructure IS 'Longitudinal section of infrastructures of a river and a type' ;
+COMMENT ON COLUMN infrastructure.group_id IS 'Reference to the infrastructure type group';
 COMMENT ON COLUMN infrastructure.year IS 'File header line info "Stand"' ;
 COMMENT ON COLUMN infrastructure.dataprovider IS 'File header line info "Datenherkunft"' ;
 COMMENT ON COLUMN infrastructure.evaluation_by IS 'File header line info "Auswerter"' ;
--- a/backend/doc/schema/postgresql-sinfo-uinfo.sql	Wed Oct 09 16:17:16 2019 +0200
+++ b/backend/doc/schema/postgresql-sinfo-uinfo.sql	Wed Oct 09 19:17:06 2019 +0200
@@ -81,6 +81,7 @@
     id  NUMERIC(9,0) PRIMARY KEY,
     river_id  integer NOT NULL CONSTRAINT cInfrastructureRivers REFERENCES rivers(id) ON DELETE CASCADE,
     annotation_type_id  integer NOT NULL CONSTRAINT cInfrastructureAnnotationType REFERENCES annotation_types(id),
+    group_id  integer NOT NULL CONSTRAINT cInfrastructureGroupAnnoType REFERENCES annotation_types(id),
     year  NUMERIC(4,0) CHECK((year >= 1700) AND (year <= 2199)),
     dataprovider  VARCHAR(256),
     evaluation_by  VARCHAR(256),
@@ -89,6 +90,7 @@
     notes  VARCHAR(256)
 );
 COMMENT ON TABLE infrastructure IS 'Longitudinal section of infrastructures of a river and a type' ;
+COMMENT ON COLUMN infrastructure.group_id IS 'Reference to the infrastructure type group';
 COMMENT ON COLUMN infrastructure.year IS 'File header line info "Stand"' ;
 COMMENT ON COLUMN infrastructure.dataprovider IS 'File header line info "Datenherkunft"' ;
 COMMENT ON COLUMN infrastructure.evaluation_by IS 'File header line info "Auswerter"' ;
--- a/backend/src/main/java/org/dive4elements/river/model/sinfo/Infrastructure.java	Wed Oct 09 16:17:16 2019 +0200
+++ b/backend/src/main/java/org/dive4elements/river/model/sinfo/Infrastructure.java	Wed Oct 09 19:17:06 2019 +0200
@@ -27,6 +27,7 @@
 
 import org.dive4elements.river.backend.SessionHolder;
 import org.dive4elements.river.model.AnnotationType;
+import org.dive4elements.river.model.Attribute.AttributeKey;
 import org.dive4elements.river.model.River;
 import org.hibernate.Query;
 import org.hibernate.Session;
@@ -58,6 +59,8 @@
 
     private AnnotationType type;
 
+    private AnnotationType group;
+
     private Integer year;
 
     private String dataprovider;
@@ -74,13 +77,13 @@
 
 
     public Infrastructure(final River river, final String filename, final String kmrange_info, final String notes, final AnnotationType type,
-            final Integer year,
-            final String dataprovider, final String evaluation_by) {
+            final AnnotationType group, final Integer year, final String dataprovider, final String evaluation_by) {
         this.river = river;
         this.filename = filename;
         this.kmrange_info = kmrange_info;
         this.notes = notes;
         this.type = type;
+        this.group = group;
         this.year = year;
         this.dataprovider = dataprovider;
         this.evaluation_by = evaluation_by;
@@ -149,6 +152,16 @@
         this.type = type;
     }
 
+    @OneToOne
+    @JoinColumn(name = "group_id")
+    public AnnotationType getGroup() {
+        return this.group;
+    }
+
+    public void setGroup(final AnnotationType group) {
+        this.group = group;
+    }
+
     @Column(name = "year")
     public Integer getYear() {
         return this.year;
@@ -213,4 +226,29 @@
         else
             return null;
     }
+
+    /**
+     * Fetches from the database the list of infrastructure types of a river's km range and river side(s)
+     * ordered by type group
+     */
+    public static List<Infrastructure> fetchInfrastructureTypes(final River river, final double kmLo, final double kmHi,
+            final AttributeKey riverside) {
+
+        final Session session = SessionHolder.HOLDER.get();
+
+        final Query query = session.createQuery("FROM Infrastructure"
+                + " WHERE (river=:river)"
+                + " AND (id IN (SELECT v.infrastructure.id FROM InfrastructureValue v"
+                + "  WHERE (v.station BETWEEN (:kmLo - 0.0001) AND (:kmHi + 0.0001))"
+                + InfrastructureValue.getRiversideClause(riverside, "v", "attr_id")
+                + "))"
+                + " ORDER BY group, type");
+        query.setParameter("river", river);
+        query.setParameter("kmLo", new Double(kmLo));
+        query.setParameter("kmHi", new Double(kmHi));
+        if (!InfrastructureValue.getRiversideClause(riverside, "v", "attr_id").isEmpty())
+            query.setParameter("attr_id", riverside.getId());
+
+        return query.list();
+    }
 }
\ No newline at end of file
--- a/backend/src/main/java/org/dive4elements/river/model/sinfo/InfrastructureValue.java	Wed Oct 09 16:17:16 2019 +0200
+++ b/backend/src/main/java/org/dive4elements/river/model/sinfo/InfrastructureValue.java	Wed Oct 09 19:17:06 2019 +0200
@@ -152,19 +152,26 @@
      */
     public static List<InfrastructureValue> getValues(final River river, final double kmLo, final double kmHi, final AttributeKey riverside) {
         final Session session = SessionHolder.HOLDER.get();
-        String riversideClause = "";
-        if ((riverside == AttributeKey.LEFT) || (riverside == AttributeKey.RIGHT))
-            riversideClause = " AND (v.attribute.id=:attr_id)";
         final Query query = session.createQuery("FROM InfrastructureValue v"
                 + " WHERE (v.infrastructure.river=:river)"
                 + " AND (v.station BETWEEN :kmLo - 0.0001 AND :kmHi + 0.0001)"
-                + riversideClause
+                + getRiversideClause(riverside, "v", "attr_id")
                 + " ORDER BY v.station, v.attribute.id");
         query.setParameter("river", river);
         query.setParameter("kmLo", new Double(kmLo));
         query.setParameter("kmHi", new Double(kmHi));
-        if (!riversideClause.isEmpty())
+        if (!getRiversideClause(riverside, "v", "attr_id").isEmpty())
             query.setParameter("attr_id", riverside.getId());
         return query.list();
     }
+
+    /**
+     * Gets a query's and-where-clause for a riverside key
+     */
+    public static String getRiversideClause(final AttributeKey riverside, final String tablealias, final String variable) {
+        if ((riverside == AttributeKey.LEFT) || (riverside == AttributeKey.RIGHT))
+            return " AND (" + tablealias + ".attribute.id=:" + variable + ")";
+        else
+            return "";
+    }
 }

http://dive4elements.wald.intevation.org