changeset 9074:766890addcb2

state To client communication;
author gernotbelger
date Fri, 18 May 2018 17:26:26 +0200
parents cd650cacc926
children 89740fe82196
files artifacts/doc/conf/artifacts/sinfo.xml artifacts/src/main/java/org/dive4elements/river/artifacts/model/CollisionHibernateFactory.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionAccess.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/LoadMultipleYearSelectState.java artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/YearChoice.java artifacts/src/main/java/org/dive4elements/river/artifacts/states/AddTableDataHelper.java artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/YearChoice.java artifacts/src/main/resources/messages.properties artifacts/src/main/resources/messages_de.properties backend/src/main/java/org/dive4elements/river/model/BedHeight.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/TableHelper.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/CollisionLoadEpochPanel.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/CollisionLoadYearPanel.java gwt-client/src/main/java/org/dive4elements/river/client/server/DataFactory.java gwt-client/src/main/java/org/dive4elements/river/client/shared/model/MultiAttributeData.java
diffstat 17 files changed, 833 insertions(+), 283 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/doc/conf/artifacts/sinfo.xml	Thu May 17 13:06:12 2018 +0200
+++ b/artifacts/doc/conf/artifacts/sinfo.xml	Fri May 18 17:26:26 2018 +0200
@@ -232,7 +232,7 @@
     </transition>
 
     <state id="state.sinfo.year_epoch" description="state.sinfo.year_epoch" state="org.dive4elements.river.artifacts.sinfo.collision.YearChoice" helpText="help.state.sinfo.year">
-      <data name="ye_select" type="String" />
+      <data name="ye_select" type="String" /> 
     </state>
 
 
@@ -251,7 +251,7 @@
 
 
     <state id="state.sinfo.load.year" description="state.sinfo.load.year" state="org.dive4elements.river.artifacts.sinfo.collision.LoadMultipleYearSelectState" helpText="help.state.sinfo.load.year">
-      <data name="years" type="String" />
+      <data name="years" type="String" /> 
     </state>
 
     <state id="state.sinfo.load.epoch" description="state.sinfo.load.epoch" state="org.dive4elements.river.artifacts.sinfo.collision.LoadMultipleEpochSelectState" helpText="help.state.sinfo.load.epoch">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/CollisionHibernateFactory.java	Fri May 18 17:26:26 2018 +0200
@@ -0,0 +1,57 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.artifacts.model;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.dive4elements.river.backend.SessionHolder;
+import org.dive4elements.river.model.River;
+import org.dive4elements.river.model.sinfo.Collision;
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public class CollisionHibernateFactory {
+
+    public static List<Collision> getCollisionsByRiver(final River river) {
+        final String queryStr = "FROM Collision WHERE river_id = :river_id";
+
+        final List<Collision> list = new ArrayList<>();
+
+        final Session session = SessionHolder.HOLDER.get();
+        try {
+            final Transaction transaction = session.beginTransaction();
+
+            final Query query = session.createQuery(queryStr);
+            query.setParameter("river_id", river.getId());
+
+            final List<Collision> collisions = query.list();
+            final Iterator<Collision> iterator = collisions.iterator();
+            while (iterator.hasNext()) {
+                final Collision coll = iterator.next();
+                // final CollisionHibernateFactory factory = new CollisionHibernateFactory(coll.getId(), coll.getYear());
+                list.add(coll);
+            }
+            transaction.commit(); // komisch, dass die Iteration davor im Code steht...
+        }
+        catch (final HibernateException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+
+}
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionAccess.java	Thu May 17 13:06:12 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/CollisionAccess.java	Fri May 18 17:26:26 2018 +0200
@@ -23,7 +23,7 @@
  *
  * @author Gernot Belger
  */
-final class CollisionAccess extends RangeAccess {
+final public class CollisionAccess extends RangeAccess {
 
     private final EpochYearAccessHelper helper;
 
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/LoadMultipleYearSelectState.java	Thu May 17 13:06:12 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/LoadMultipleYearSelectState.java	Fri May 18 17:26:26 2018 +0200
@@ -8,10 +8,20 @@
 
 package org.dive4elements.river.artifacts.sinfo.collision;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.log4j.Logger;
 import org.dive4elements.artifacts.Artifact;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
+import org.dive4elements.river.artifacts.model.CollisionHibernateFactory;
 import org.dive4elements.river.artifacts.sinfo.SINFOArtifact;
+import org.dive4elements.river.artifacts.states.AddTableDataHelper;
 import org.dive4elements.river.artifacts.states.DefaultState;
+import org.dive4elements.river.model.sinfo.Collision;
+import org.w3c.dom.Element;
 
 /** State in which to fetch years for sedminent load calculation. */
 public class LoadMultipleYearSelectState extends DefaultState {
@@ -28,22 +38,55 @@
     /** Year Select Widget. */
     @Override
     protected String getUIProvider() {
-        return "minfo.sedimentload_year_select"; // TODO: eigenes Panel oder allgemeineren Code
+        return "sinfo.collision.load_year_select";
     }
 
     @Override
-    public boolean validate(final Artifact artifact) throws IllegalArgumentException {
+    protected void appendItems(final Artifact artifact, final ElementCreator creator, final String name, final CallContext context, final Element select) {
+
+        try {
+            if ("years".equals(name)) {
+
+                final AddTableDataHelper helper = new AddTableDataHelper(creator, select, "year", context.getMeta());
+
+                helper.addColumn(0, "pinfrom", "60", "common.client.ui.selection", "ICON", "CENTER", "from");
+                helper.addColumn(1, "year", "80", "year", "INTEGER", "RIGHT", null);
+
+                final CollisionAccess access = new CollisionAccess((SINFOArtifact) artifact); // Der River wurde im vorigen State bereits gesetzt
+
+                final List<Collision> collisions = CollisionHibernateFactory.getCollisionsByRiver(access.getRiver());
+                for (final Collision coll : collisions) {
+                    final Integer year = coll.getYear();
+                    final Map<String, String> row = new HashMap<>();
+                    row.put("year", year.toString()); // Nullpointer?
+                    try {
+                        helper.addRow(row);
+                    }
+                    catch (final Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+                helper.submitMapToXml();
+            }
+        }
+        catch (final IllegalArgumentException iae) {
+            iae.printStackTrace();
+        }
+    }
+
+    @Override
+    public void validate(final Artifact artifact, final CallContext cc) throws IllegalArgumentException {
         // TODO: check verstehen
 
         final CollisionAccess access = new CollisionAccess((SINFOArtifact) artifact);
 
         // Second year should be later than first.
 
-        if (access.getYears() == null || access.getYears().length == 0)
-            return true;
+        // if (access.getYears() == null || access.getYears().length == 0)
+        // return true;
         // throw new IllegalArgumentException("error_years_wrong");
 
-        return true;
+        // return true;
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/YearChoice.java	Thu May 17 13:06:12 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/collision/YearChoice.java	Fri May 18 17:26:26 2018 +0200
@@ -29,6 +29,6 @@
         entries.add("state.sinfo.year");
         entries.add("state.sinfo.epoch");
         return entries;
+    }
 
-    }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/AddTableDataHelper.java	Fri May 18 17:26:26 2018 +0200
@@ -0,0 +1,96 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.artifacts.states;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.w3c.dom.Element;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public class AddTableDataHelper {
+
+    private final ElementCreator creator;
+    private final Element select;
+    private final CallMeta callmeta;
+    // Create Metadata:
+    final Map<String, Map<String, String>> meta = new HashMap<>();
+    final List<String> columnValidList = new ArrayList<>();
+
+    public AddTableDataHelper(final ElementCreator creator, final Element select, final String pinKeyColumn, final CallMeta callMeta) {
+        this.creator = creator;
+        this.select = select;
+        this.callmeta = callMeta;
+        creator.addAttr(select, "type", "multiattribute", true);
+
+        final Map<String, String> metaTableInfo = new HashMap<>();
+        metaTableInfo.put("keycol", pinKeyColumn);
+        this.meta.put("meta_tableinfo", metaTableInfo);
+
+    }
+
+    public void submitMapToXml() {
+
+        final Element meta = this.creator.create("meta");
+
+        for (final Entry<String, Map<String, String>> entry : this.meta.entrySet()) {
+            final String name = entry.getKey(); // z.B. Spaltenname
+            final Map<String, String> keyValueMap = entry.getValue();
+            final Element element = this.creator.create(name);
+
+            for (final Entry<String, String> kventry : keyValueMap.entrySet()) {
+                this.creator.addAttr(element, kventry.getKey(), kventry.getValue());
+            }
+            meta.appendChild(element);
+        }
+
+        this.select.appendChild(meta);
+
+    }
+
+    public void addRow(final Map<String, String> colValMap) throws Exception {
+
+        final Element item = this.creator.create("item");
+
+        for (final Entry<String, String> entry : colValMap.entrySet()) {
+            if (this.meta.containsKey(entry.getKey())) {
+                this.creator.addAttr(item, entry.getKey(), entry.getValue() != null ? entry.getValue().toString() : "");
+            } else {
+                throw new Exception("Error: No such column " + entry.getKey());
+            }
+        }
+        this.select.appendChild(item);
+    }
+
+    public void addColumn(final int order, final String rootHashmapKey, final String colWidth, final String translationKeyFromMessages, final String type,
+            final String alignment, final String pinType) {
+
+        final Map<String, String> map = new HashMap<>();
+        map.put("colwidth", colWidth);
+        final String translation = Resources.getMsg(this.callmeta, translationKeyFromMessages);
+        map.put("translation", translation);
+        map.put("type", type);
+        map.put("alignment", alignment);
+        map.put("order", Integer.toString(order));
+        map.put("pin", pinType);
+        this.meta.put(rootHashmapKey, map);
+
+    }
+
+}
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/YearChoice.java	Thu May 17 13:06:12 2018 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/uinfo/inundationduration/YearChoice.java	Fri May 18 17:26:26 2018 +0200
@@ -29,6 +29,6 @@
         entries.add("state.uinfo.year");
         entries.add("state.uinfo.totalepoch");
         return entries;
+    }
 
-    }
 }
\ No newline at end of file
--- a/artifacts/src/main/resources/messages.properties	Thu May 17 13:06:12 2018 +0200
+++ b/artifacts/src/main/resources/messages.properties	Fri May 18 17:26:26 2018 +0200
@@ -1118,4 +1118,6 @@
 help.state.bundu.vollmer.function=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.function
 help.state.bundu.vollmer.preprocessing=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.preprocessing
 help.state.bundu.vollmer.qs=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.qs
-help.state.bundu.vollmer.compute=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.compute
\ No newline at end of file
+help.state.bundu.vollmer.compute=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.compute
+
+common.client.ui.selection = Selection
\ No newline at end of file
--- a/artifacts/src/main/resources/messages_de.properties	Thu May 17 13:06:12 2018 +0200
+++ b/artifacts/src/main/resources/messages_de.properties	Fri May 18 17:26:26 2018 +0200
@@ -1118,4 +1118,6 @@
 help.state.bundu.vollmer.function=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.function
 help.state.bundu.vollmer.preprocessing=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.preprocessing
 help.state.bundu.vollmer.qs=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.qs
-help.state.bundu.vollmer.compute=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.compute
\ No newline at end of file
+help.state.bundu.vollmer.compute=${help.url}/OnlineHilfe/bunduierungsanalyse#help.state.bundu.vollmer.compute
+
+common.client.ui.selection = Auswahl
\ No newline at end of file
--- a/backend/src/main/java/org/dive4elements/river/model/BedHeight.java	Thu May 17 13:06:12 2018 +0200
+++ b/backend/src/main/java/org/dive4elements/river/model/BedHeight.java	Fri May 18 17:26:26 2018 +0200
@@ -27,7 +27,6 @@
 import org.hibernate.Query;
 import org.hibernate.Session;
 
-
 @Entity
 @Table(name = "bed_height")
 public class BedHeight implements Serializable {
@@ -40,7 +39,7 @@
 
     private River river;
 
-    private BedHeightType  type;
+    private BedHeightType type;
 
     private LocationSystem locationSystem;
 
@@ -55,35 +54,30 @@
 
     private List<BedHeightValue> values;
 
-
     public BedHeight() {
     }
 
-
     public BedHeight(final River river, final Integer year, final BedHeightType type, final LocationSystem locationSystem,
-            final ElevationModel curElevationModel,
-            final Range range) {
+            final ElevationModel curElevationModel, final Range range) {
         this(river, year, type, locationSystem, curElevationModel, null, range, null, null, null, null);
     }
 
-
     public BedHeight(final River river, final Integer year, final BedHeightType type, final LocationSystem locationSystem,
             final ElevationModel curElevationModel, final ElevationModel oldElevationModel, final Range range, final String evaluationBy,
             final String description, final String sounding_width_info, final String notes) {
-        this.river             = river;
-        this.year              = year;
-        this.type              = type;
-        this.locationSystem    = locationSystem;
+        this.river = river;
+        this.year = year;
+        this.type = type;
+        this.locationSystem = locationSystem;
         this.curElevationModel = curElevationModel;
         this.oldElevationModel = oldElevationModel;
-        this.range             = range;
-        this.evaluationBy      = evaluationBy;
-        this.description       = description;
+        this.range = range;
+        this.evaluationBy = evaluationBy;
+        this.description = description;
         this.sounding_width_info = sounding_width_info;
         this.notes = notes;
     }
 
-
     @Id
     @SequenceGenerator(name = "SEQUENCE_BED_HEIGHT_ID_SEQ", sequenceName = "BED_HEIGHT_ID_SEQ", allocationSize = 1)
     @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_BED_HEIGHT_ID_SEQ")
@@ -211,26 +205,20 @@
         this.values = values;
     }
 
-
-    public static List<BedHeight> getBedHeights(
-            final River  river,
-            final double kmLo,
-            final double kmHi
-            ) {
+    public static List<BedHeight> getBedHeights(final River river, final double kmLo, final double kmHi) {
         final Session session = SessionHolder.HOLDER.get();
 
-        final Query query = session.createQuery(
-                "from BedHeight where river=:river");
+        final Query query = session.createQuery("from BedHeight where river=:river");
 
         query.setParameter("river", river);
 
         // TODO Do km range filtering in SQL statement
 
         final List<BedHeight> singles = query.list();
-        final List<BedHeight> good    = new ArrayList<>();
+        final List<BedHeight> good = new ArrayList<>();
 
-        for (final BedHeight s: singles) {
-            for (final BedHeightValue value: s.getValues()) {
+        for (final BedHeight s : singles) {
+            for (final BedHeightValue value : s.getValues()) {
                 final double station = value.getStation().doubleValue();
 
                 if (station >= kmLo && station <= kmHi) {
@@ -243,12 +231,10 @@
         return good;
     }
 
-
     public static BedHeight getBedHeightById(final int id) {
         final Session session = SessionHolder.HOLDER.get();
 
-        final Query query = session.createQuery(
-                "from BedHeight where id=:id");
+        final Query query = session.createQuery("from BedHeight where id=:id");
 
         query.setParameter("id", id);
 
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java	Thu May 17 13:06:12 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java	Fri May 18 17:26:26 2018 +0200
@@ -254,7 +254,6 @@
                 return d;
             }
         }
-
         return null;
     }
 
@@ -300,7 +299,7 @@
 
     /**
      * Validates the selection.
-     * 
+     *
      * @return List of internationalized errror messages (if any).
      */
     public List<String> validate() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/TableHelper.java	Fri May 18 17:26:26 2018 +0200
@@ -0,0 +1,30 @@
+/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde
+ * Software engineering by
+ *  Björnsen Beratende Ingenieure GmbH
+ *  Dr. Schumacher Ingenieurbüro für Wasser und Umwelt
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+package org.dive4elements.river.client.client.ui;
+
+import com.smartgwt.client.widgets.grid.ListGrid;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public class TableHelper {
+
+    private enum PinType {
+        none, from, to
+    }
+
+    private ListGrid table;
+
+    public TableHelper() {
+
+    }
+
+}
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java	Thu May 17 13:06:12 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java	Fri May 18 17:26:26 2018 +0200
@@ -23,6 +23,7 @@
 import org.dive4elements.river.client.client.ui.minfo.SedLoadPeriodPanel;
 import org.dive4elements.river.client.client.ui.minfo.SedLoadSQTiPanel;
 import org.dive4elements.river.client.client.ui.sinfo.CollisionLoadEpochPanel;
+import org.dive4elements.river.client.client.ui.sinfo.CollisionLoadYearPanel;
 import org.dive4elements.river.client.client.ui.sinfo.FlowDepthMinMaxTwinPanel;
 import org.dive4elements.river.client.client.ui.sinfo.FlowDepthTwinPanel;
 import org.dive4elements.river.client.client.ui.sq.SQPeriodPanel;
@@ -154,6 +155,8 @@
             return new SedLoadPeriodPanel();
         } else if (uiProvider.equals("minfo.sedimentload_epoch_select")) {
             return new SedLoadEpochPanel();
+        } else if (uiProvider.equals("sinfo.collision.load_year_select")) {
+            return new CollisionLoadYearPanel();
         } else if (uiProvider.equals("sinfo.collision.load_epoch_select")) {
             return new CollisionLoadEpochPanel();
         } else if (uiProvider.equals("uinfo.inundation_duration.load_epoch_select")) {
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/CollisionLoadEpochPanel.java	Thu May 17 13:06:12 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/CollisionLoadEpochPanel.java	Fri May 18 17:26:26 2018 +0200
@@ -46,6 +46,7 @@
 import com.smartgwt.client.widgets.layout.HLayout;
 import com.smartgwt.client.widgets.layout.VLayout;
 
+// FIXME: copy of SedLoadEpochPanel
 public class CollisionLoadEpochPanel extends AbstractUIProvider {
     protected SedimentLoadInfoServiceAsync sedLoadInfoService = GWT.create(SedimentLoadInfoService.class);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/CollisionLoadYearPanel.java	Fri May 18 17:26:26 2018 +0200
@@ -0,0 +1,397 @@
+/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU AGPL (>=v3)
+ * and comes with ABSOLUTELY NO WARRANTY! Check out the
+ * documentation coming with Dive4Elements River for details.
+ */
+
+package org.dive4elements.river.client.client.ui.sinfo;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.dive4elements.river.client.client.FLYSConstants;
+import org.dive4elements.river.client.client.ui.AbstractUIProvider;
+import org.dive4elements.river.client.client.ui.ParameterMatrix.Column;
+import org.dive4elements.river.client.shared.model.Data;
+import org.dive4elements.river.client.shared.model.DataItem;
+import org.dive4elements.river.client.shared.model.DataList;
+import org.dive4elements.river.client.shared.model.DefaultData;
+import org.dive4elements.river.client.shared.model.DefaultDataItem;
+import org.dive4elements.river.client.shared.model.MultiAttributeData;
+import org.dive4elements.river.client.shared.model.MultiDataItem;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.smartgwt.client.data.Record;
+import com.smartgwt.client.types.Alignment;
+import com.smartgwt.client.types.ListGridFieldType;
+import com.smartgwt.client.widgets.Canvas;
+import com.smartgwt.client.widgets.Label;
+import com.smartgwt.client.widgets.form.DynamicForm;
+import com.smartgwt.client.widgets.form.fields.TextItem;
+import com.smartgwt.client.widgets.form.validator.IsIntegerValidator;
+import com.smartgwt.client.widgets.grid.ListGrid;
+import com.smartgwt.client.widgets.grid.ListGridField;
+import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
+import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
+import com.smartgwt.client.widgets.layout.HLayout;
+import com.smartgwt.client.widgets.layout.VLayout;
+
+public class CollisionLoadYearPanel extends AbstractUIProvider {
+
+    public interface IColumnClickHandler {
+        void columnClicked(String value);
+    }
+
+    private enum PinType {
+        none, from, to
+    }
+
+    private final FLYSConstants MESSAGES = GWT.create(FLYSConstants.class);
+
+    private TextItem yearsItem;
+
+    private final List<String> validYears = new ArrayList<String>();
+
+    private ListGrid table;
+
+    public CollisionLoadYearPanel() {
+    }
+
+    @Override
+    public Canvas createOld(final DataList dataList) {
+        final List<Data> items = dataList.getAll();
+        final Data years = getData(items, "years");
+        final DataItem[] yearsItems = years.getItems();
+
+        final String v1 = yearsItems[0].getStringValue().replace(" ", ", ");
+
+        final Label old = new Label(v1);
+        final HLayout layout = new HLayout();
+        layout.setWidth("400px");
+
+        final Label label = new Label(dataList.getLabel());
+        label.setWidth("200px");
+
+        final Canvas back = getBackButton(dataList.getState());
+
+        layout.addMember(label);
+        layout.addMember(old);
+        layout.addMember(back);
+
+        return layout;
+    }
+
+    @Override
+    public List<String> validate() {
+        return validateYears();
+    }
+
+    @Override
+    public Canvas create(final DataList data) {
+        final VLayout layout = new VLayout();
+
+        final Canvas helper = createHelper(data);
+
+        this.helperContainer.addMember(helper);
+
+        final Canvas submit = getNextButton();
+        final Canvas widget = createWidget(data);
+
+        layout.addMember(widget);
+        layout.addMember(submit);
+
+        return layout;
+    }
+
+    private Canvas createHelper(final DataList dataList) {
+        this.table = new ListGrid();
+        this.table.setShowHeaderContextMenu(false);
+        this.table.setWidth100();
+        this.table.setShowRecordComponents(true);
+        this.table.setShowRecordComponentsByCell(true);
+        this.table.setHeight100();
+        this.table.setEmptyMessage(this.MSG.empty_table());
+        this.table.setCanReorderFields(false);
+
+        final MultiAttributeData mData = findDefinition(dataList, "years");
+        final Map<String, Map<String, String>> meta = mData.getMeta();
+
+        final Map<String, String> tableInfo = meta.get("meta_tableinfo");
+        final String keyColumnName = tableInfo.get("keycol");
+
+        final IColumnClickHandler fromHandler = new IColumnClickHandler() { // add to external class
+
+            @Override
+            public void columnClicked(final String value) {
+                appendYear(value);
+            }
+        };
+
+        final SortedMap<Integer, ListGridField> fields = new TreeMap<Integer, ListGridField>();
+
+        for (final Entry<String, Map<String, String>> entry : meta.entrySet()) {
+
+            final String colName = entry.getKey();
+            if (colName.startsWith("meta_"))
+                continue;
+
+            final Map<String, String> values = entry.getValue();
+
+            final int order = Integer.parseInt(values.get("order"));
+
+            final ListGridField field = createField(colName, keyColumnName, values, fromHandler);
+
+            fields.put(order, field);
+        }
+
+        for (final DataItem dataItem : mData.opts) {
+            final MultiDataItem item = (MultiDataItem) dataItem;
+
+            final Map<String, String> valueMap = item.getValue();
+            // final String columnName = mData.getLabel();
+            final Record newRecord = new Record();
+            for (final Entry<String, String> entry : valueMap.entrySet()) {
+                final String key = entry.getKey();
+                final String value = entry.getValue();
+                newRecord.setAttribute(key, value);
+
+                if (key.equals(keyColumnName))
+                    this.validYears.add(value);
+            }
+
+            this.table.addData(newRecord);
+        }
+
+        this.table.setFields(fields.values().toArray(new ListGridField[fields.size()]));
+
+        return this.table;
+    }
+
+    private MultiAttributeData findDefinition(final DataList dataList, final String paranemterName) {
+
+        for (final Data data : dataList.getAll()) {
+
+            final String label = data.getLabel();
+            if (label.equals(paranemterName) && data instanceof MultiAttributeData)
+                return (MultiAttributeData) data;
+        }
+
+        return null;
+    }
+
+    private ListGridField createField(final String colName, final String keyColumnName, final Map<String, String> values,
+            final IColumnClickHandler fromHandler) {
+
+        final String translation = getMeta(values, "translation", colName);
+
+        final ListGridField field = new ListGridField(colName, translation);
+
+        final String width = getMeta(values, "width", "99");
+        field.setWidth(width);
+
+        final ListGridFieldType type = getMeta(values, "type", ListGridFieldType.TEXT, ListGridFieldType.class);
+        field.setType(type);
+
+        final Alignment alignment = getMeta(values, "alignment", Alignment.LEFT, Alignment.class);
+        field.setAlign(alignment);
+
+        final PinType pinType = getMeta(values, "pin", PinType.none, PinType.class);
+        switch (pinType) {
+        case from: {
+            final String baseUrl = GWT.getHostPageBaseURL();
+            field.setCellIcon(baseUrl + this.MESSAGES.markerGreen());
+            field.addRecordClickHandler(new RecordClickHandler() {
+                @Override
+                public void onRecordClick(final RecordClickEvent e) {
+                    final Record r = e.getRecord();
+                    fromHandler.columnClicked(r.getAttribute(keyColumnName));
+                }
+            });
+        }
+            break;
+
+        case to:
+            break;
+
+        case none:
+        default:
+            break;
+        }
+
+        return field;
+    }
+
+    private String getMeta(final Map<String, String> values, final String key, final String defaultValue) {
+
+        final String value = values.get(key);
+        if (value == null || value.isEmpty())
+            return defaultValue;
+
+        return value;
+    }
+
+    private <TYPE extends Enum<TYPE>> TYPE getMeta(final Map<String, String> values, final String key, final TYPE defaultValue, final Class<TYPE> enumType) {
+
+        final String value = values.get(key);
+        if (value == null || value.isEmpty())
+            return defaultValue;
+
+        try {
+            return Enum.valueOf(enumType, value);
+        }
+        catch (final Exception e) {
+            e.printStackTrace();
+            return defaultValue;
+        }
+    }
+
+    private Map<String, Column> columns;
+    private List<String> columnNames;
+    private List<String> valueNames;
+    private Map<String, List<String>> attributes;
+    private Map<String, List<String>> selected;
+
+    public void addColumn(final MultiAttributeData options) {
+        GWT.log("Add Columns for MultiAttribute data");
+
+        this.columns = new HashMap<String, Column>();
+        this.columnNames = new ArrayList<String>();
+        this.valueNames = new ArrayList<String>();
+        this.selected = new HashMap<String, List<String>>();
+        this.attributes = new HashMap<String, List<String>>();
+
+        final String groupTitle = options.getLabel();
+
+        final Column col = new Column(groupTitle);
+        final DataItem[] items = options.getItems();
+
+        if (items == null) {
+            GWT.log("No items found in StringOptionsData '" + groupTitle + "'");
+            return;
+        }
+
+        final MultiDataItem mItem = (MultiDataItem) items[0];
+        for (final Map.Entry<String, String> entry : mItem.getValue().entrySet()) {
+            if (entry.getKey().equals("art:value") || entry.getKey().equals("art:label")) {
+                continue;
+            }
+            this.attributes.put(entry.getKey(), new ArrayList<String>());
+        }
+        for (final DataItem item : items) {
+            GWT.log("multidataitem: " + item.getLabel());
+            final String title = item.getLabel();
+
+            if (this.valueNames.indexOf(title) < 0) {
+                this.valueNames.add(title);
+            }
+            final MultiDataItem mi = (MultiDataItem) item;
+            final Map<String, String> vs = mi.getValue();
+            for (final Map.Entry<String, String> e : vs.entrySet()) {
+                if (e.getKey().equals("art:value") || e.getKey().equals("art:label")) {
+                    continue;
+                }
+                final List<String> data = this.attributes.get(e.getKey());
+                data.add(e.getValue());
+            }
+            col.addValue(item.getLabel(), mi.getValue().get("art:value"));
+        }
+
+        this.columnNames.add(groupTitle);
+        this.columns.put(groupTitle, col);
+    }
+
+    public Canvas createWidget(final DataList data) {
+        final VLayout layout = new VLayout();
+
+        final Label title = new Label(data.get(0).getDescription());
+        title.setHeight("25px");
+
+        final DynamicForm form = new DynamicForm();
+        form.setNumCols(4);
+        this.yearsItem = new TextItem(this.MSG.years());
+        this.yearsItem.setValidators(new IsIntegerValidator());
+        form.setFields(this.yearsItem);
+
+        layout.addMember(title);
+        layout.addMember(form);
+
+        return layout;
+    }
+
+    @Override
+    protected Data[] getData() {
+        validateYears();
+        if (this.yearsItem != null && !this.yearsItem.getValueAsString().isEmpty()) {
+            final List<Data> data = new ArrayList<Data>();
+
+            final DataItem yearsdata = new DefaultDataItem("years", "years", this.yearsItem.getValueAsString().trim());
+            data.add(new DefaultData("years", null, null, new DataItem[] { yearsdata }));
+
+            return data.toArray(new Data[data.size()]);
+        }
+        return new Data[0];
+    }
+
+    private List<String> validateYears() {
+        final List<String> errors = new ArrayList<String>();
+        final NumberFormat nf = NumberFormat.getDecimalFormat();
+
+        if (this.yearsItem.getValueAsString() == null || this.yearsItem.getValueAsString().trim().isEmpty()) {
+            errors.add(this.MESSAGES.empty_filter());
+            return errors;
+        }
+
+        final String[] sValues = this.yearsItem.getValueAsString().trim().split(" ");
+        String filtered = "";
+        int goodValues = 0;
+        for (final String sValue : sValues) {
+            int value;
+            try {
+                value = Integer.parseInt(sValue);
+            }
+            catch (final NumberFormatException e) {
+                errors.add(this.MESSAGES.wrongFormat() + ": " + sValue);
+                continue;
+            }
+            boolean isGood = false;
+            for (final String validYear : this.validYears) {
+                /* No list contains for strings? */
+                if (sValue.equals(validYear)) {
+                    isGood = true;
+                    break;
+                }
+            }
+            if (!isGood) {
+                String tmp = this.MESSAGES.no_data_for_year();
+                tmp = tmp.replace("$1", sValue);
+                errors.add(tmp);
+                continue;
+            }
+            goodValues++;
+            if (goodValues > 1) {
+                filtered += " " + Integer.toString(value);
+            } else {
+                filtered = Integer.toString(value);
+            }
+        }
+
+        return errors;
+    }
+
+    protected final void appendYear(final String year) {
+        final String oldYears = this.yearsItem.getValueAsString();
+        if (oldYears != null && !oldYears.isEmpty()) {
+            this.yearsItem.setValue(oldYears.trim() + " " + year);
+        } else {
+            this.yearsItem.setValue(year);
+        }
+    }
+}
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/DataFactory.java	Thu May 17 13:06:12 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/DataFactory.java	Fri May 18 17:26:26 2018 +0200
@@ -14,11 +14,6 @@
 
 import javax.xml.xpath.XPathConstants;
 
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 import org.apache.log4j.Logger;
 import org.dive4elements.artifacts.common.ArtifactNamespaceContext;
 import org.dive4elements.artifacts.common.utils.XMLUtils;
@@ -27,16 +22,21 @@
 import org.dive4elements.river.client.shared.model.DefaultData;
 import org.dive4elements.river.client.shared.model.DefaultDataItem;
 import org.dive4elements.river.client.shared.model.DoubleArrayData;
+import org.dive4elements.river.client.shared.model.IntDataItem;
 import org.dive4elements.river.client.shared.model.IntegerArrayData;
 import org.dive4elements.river.client.shared.model.IntegerData;
 import org.dive4elements.river.client.shared.model.IntegerOptionsData;
 import org.dive4elements.river.client.shared.model.IntegerRangeData;
+import org.dive4elements.river.client.shared.model.LongRangeData;
 import org.dive4elements.river.client.shared.model.MultiAttributeData;
 import org.dive4elements.river.client.shared.model.MultiDataItem;
 import org.dive4elements.river.client.shared.model.StringData;
 import org.dive4elements.river.client.shared.model.StringOptionsData;
-import org.dive4elements.river.client.shared.model.LongRangeData;
-import org.dive4elements.river.client.shared.model.IntDataItem;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
@@ -47,18 +47,18 @@
 
     public static final String NS_URI = ArtifactNamespaceContext.NAMESPACE_URI;
 
-
     /**
      * Creates a new Data instance based on the <i>art:type</i> attribute of
      * <i>element</i>.
      *
-     * @param element The Data element.
+     * @param element
+     *            The Data element.
      *
      * @return a Data instance.
      */
-    public static Data createDataFromElement(Element element) {
-        String name  = element.getAttributeNS(NS_URI, "name");
-        String type  = element.getAttributeNS(NS_URI, "type");
+    public static Data createDataFromElement(final Element element) {
+        final String name = element.getAttributeNS(NS_URI, "name");
+        String type = element.getAttributeNS(NS_URI, "type");
         String label = element.getAttributeNS(NS_URI, "label");
 
         label = label != null && label.length() > 0 ? label : name;
@@ -74,279 +74,233 @@
 
             if (type.equals(StringData.TYPE)) {
                 return createStringData(element, name, label);
-            }
-            else if (type.equals(IntegerData.TYPE)) {
+            } else if (type.equals(IntegerData.TYPE)) {
                 return createIntegerData(element, name, label);
-            }
-            else if (type.equals(StringOptionsData.TYPE)) {
+            } else if (type.equals(StringOptionsData.TYPE)) {
                 return createStringOptionsData(element, name, label);
-            }
-            else if (type.equals(IntegerOptionsData.TYPE)) {
+            } else if (type.equals(IntegerOptionsData.TYPE)) {
                 return createIntegerOptionsData(element, name, label);
-            }
-            else if (type.equals(IntegerRangeData.TYPE)) {
+            } else if (type.equals(IntegerRangeData.TYPE)) {
                 return createIntegerRangeData(element, name, label);
-            }
-            else if (type.equals(IntegerArrayData.TYPE)) {
+            } else if (type.equals(IntegerArrayData.TYPE)) {
                 return createIntegerArrayData(element, name, label);
-            }
-            else if (type.equals(DoubleArrayData.TYPE)) {
+            } else if (type.equals(DoubleArrayData.TYPE)) {
                 return createDoubleArrayData(element, name, label);
-            }
-            else if (type.equals(LongRangeData.TYPE)) {
+            } else if (type.equals(LongRangeData.TYPE)) {
                 return createLongRangeData(element, name, label);
-            }
-            else if (type.equals(MultiAttributeData.TYPE)) {
+            } else if (type.equals(MultiAttributeData.TYPE)) {
                 return createMultiAttributeData(element, name, label);
-            }
-            else {
+            } else {
                 return createDefaultData(element, name, label);
             }
         }
-        catch (Exception e) {
+        catch (final Exception e) {
             log.error("Error while data creation for: " + name);
         }
 
         return null;
     }
 
-
-    public static Data createMultiAttributeData(
-        Element element,
-        String name,
-        String label) {
-        return new MultiAttributeData(
-            name,
-            label,
-            extractMultiDataItems(element),
-            extractMeta(element));
+    public static Data createMultiAttributeData(final Element element, final String name, final String label) {
+        return new MultiAttributeData(name, label, extractMultiDataItems(element), extractMeta(element));
     }
 
-
-    private static Map<String, Map<String, String>> extractMeta(
-        Element element
-    ) {
-        NodeList nl = element.getElementsByTagName("meta");
-        int N = nl.getLength();
-        if (N < 1) {
-            log.debug("No meta data found for multi attribute data");
+    private static Map<String, Map<String, String>> extractMeta(final Element element) {
+        final NodeList nl = element.getElementsByTagName("art:meta");
+        final int N = nl.getLength();
+        if (N != 1) {
+            log.debug("No or too much meta data found for multi attribute data");
             return Collections.<String, Map<String, String>>emptyMap();
         }
-        Map<String, Map<String, String>> map =
-            new HashMap<String, Map<String, String>>();
+        final Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();
 
-        for (int i = 0; i < N; ++i) {
-            Element e = (Element)nl.item(i);
-            NamedNodeMap attrs = e.getAttributes();
-            Map<String, String> kvs = new HashMap<String, String>();
-            for (int j = 0, A = attrs.getLength(); j < A; ++j) {
-                Attr attr = (Attr)attrs.item(j);
-                kvs.put(attr.getName(), attr.getValue());
+        final Element metaElement = (Element) nl.item(0);
+        final NodeList metaChildren = metaElement.getChildNodes();
+
+        for (int i = 0; i < metaChildren.getLength(); ++i) {
+
+            final Node childNode = metaChildren.item(i);
+            if (childNode instanceof Element) {
+
+                final Element e = (Element) childNode;
+                final NamedNodeMap attrs = e.getAttributes();
+                final Map<String, String> kvs = new HashMap<String, String>();
+                for (int j = 0, A = attrs.getLength(); j < A; ++j) {
+                    final Attr attr = (Attr) attrs.item(j);
+                    kvs.put(attr.getName(), attr.getValue());
+                }
+                map.put(e.getLocalName(), kvs);
             }
-            map.put(e.getTagName(), kvs);
         }
 
         return map;
     }
 
-
-    protected static DataItem[] extractMultiDataItems(Element element) {
-        NodeList itemList = (NodeList) XMLUtils.xpath(
-            element,
-            "art:item",
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
+    protected static DataItem[] extractMultiDataItems(final Element element) {
+        final NodeList itemList = (NodeList) XMLUtils.xpath(element, "art:item", XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE);
 
         if (itemList == null || itemList.getLength() == 0) {
             log.debug("No old data items found.");
             return null;
         }
 
-        int count = itemList.getLength();
-
-        MultiDataItem[] items = new MultiDataItem[count];
-
-         for (int i = 0; i < count; i++) {
-             Element tmp = (Element) itemList.item(i);
+        final int count = itemList.getLength();
 
-             HashMap<String, String> data = new HashMap<String, String>();
-             String label = tmp.getAttributeNS(NS_URI, "label");
-             NamedNodeMap attributes = tmp.getAttributes();
-             for (int j = 0, L = attributes.getLength(); j < L; j++) {
-                 Node n = attributes.item(j);
-                 if (n.getNodeName().equals("label")) {
-                     continue;
-                 }
-                 data.put(n.getNodeName(), n.getNodeValue());
-             }
-             items[i] = new MultiDataItem(label, label, data);
-         }
-         return items;
+        final MultiDataItem[] items = new MultiDataItem[count];
+
+        for (int i = 0; i < count; i++) {
+            final Element tmp = (Element) itemList.item(i);
+
+            final HashMap<String, String> data = new HashMap<String, String>();
+            final String label = tmp.getAttributeNS(NS_URI, "label");
+            final NamedNodeMap attributes = tmp.getAttributes();
+            for (int j = 0, L = attributes.getLength(); j < L; j++) {
+                final Node n = attributes.item(j);
+                if (n.getNodeName().equals("label")) {
+                    continue;
+                }
+                data.put(n.getNodeName(), n.getNodeValue());
+            }
+            items[i] = new MultiDataItem(label, label, data);
+        }
+        return items;
     }
 
-
     /**
      * This method creates a new instance of DefaultData which has no real type
      * set.
      *
-     * @param ele The Data element.
-     * @param name The name of the Data instance.
+     * @param ele
+     *            The Data element.
+     * @param name
+     *            The name of the Data instance.
      *
      * @return an instance of DefaultData.
      */
-    protected static Data createDefaultData(
-        Element ele,
-        String name,
-        String label
-    ) {
+    protected static Data createDefaultData(final Element ele, final String name, final String label) {
         log.debug("Create new DefaultData");
         return new DefaultData(name, label, "default", extractDataItems(ele));
     }
 
-
     /**
      * This method creates a new instance of StringData which has a type
      * "string" set.
      *
-     * @param ele The Data element.
-     * @param name The name of the Data instance.
+     * @param ele
+     *            The Data element.
+     * @param name
+     *            The name of the Data instance.
      *
      * @return an instance of StringData.
      */
-    protected static Data createStringData(
-        Element ele,
-        String name,
-        String label
-    ) {
+    protected static Data createStringData(final Element ele, final String name, final String label) {
         return new StringData(name, label, extractDataItems(ele));
     }
 
-
     /**
      * This method creates a new instance of DefaultData which has a type
      * "integer" set.
      *
-     * @param ele The Data element.
-     * @param name The name of the Data instance.
+     * @param ele
+     *            The Data element.
+     * @param name
+     *            The name of the Data instance.
      *
      * @return an instance of IntegerData.
      */
-    protected static Data createIntegerData(
-        Element ele,
-        String name,
-        String label
-    ) {
+    protected static Data createIntegerData(final Element ele, final String name, final String label) {
         return new IntegerData(name, label, extractDataItems(ele));
     }
 
-
     /**
      * This method creates a new instance of StringOptionsData which has a type
      * "options" set.
      *
-     * @param ele The Data element.
-     * @param name The name of the Data instance.
+     * @param ele
+     *            The Data element.
+     * @param name
+     *            The name of the Data instance.
      *
      * @return an instance of StringOptionsData.
      */
-    protected static Data createStringOptionsData(
-        Element ele,
-        String name,
-        String label
-    ) {
+    protected static Data createStringOptionsData(final Element ele, final String name, final String label) {
         return new StringOptionsData(name, label, extractDataItems(ele));
     }
 
-
     /**
      * This method creates a new instance of DefaultData which has a type
      * "intoptions" set.
      *
-     * @param ele The Data element.
-     * @param name The name of the Data instance.
+     * @param ele
+     *            The Data element.
+     * @param name
+     *            The name of the Data instance.
      *
      * @return an instance of IntegerOptionsData.
      */
-    protected static Data createIntegerOptionsData(
-        Element ele,
-        String name,
-        String label
-    ) {
+    protected static Data createIntegerOptionsData(final Element ele, final String name, final String label) {
         return new IntegerOptionsData(name, label, extractDataItems(ele));
     }
 
-
     /**
      * This method creates a new instance of DefaultData which has a type
      * "intrange" set.
      *
-     * @param ele The Data element.
-     * @param name The name of the Data instance.
+     * @param ele
+     *            The Data element.
+     * @param name
+     *            The name of the Data instance.
      *
      * @return an instance of IntegerRangeData.
      */
-    protected static Data createIntegerRangeData(
-        Element ele,
-        String name,
-        String label
-    ) {
-        DataItem[] items    = extractDataItems(ele);
-        String     rawValue = items[0].getStringValue();
+    protected static Data createIntegerRangeData(final Element ele, final String name, final String label) {
+        final DataItem[] items = extractDataItems(ele);
+        final String rawValue = items[0].getStringValue();
 
-        String[] minmax = rawValue.split(";");
+        final String[] minmax = rawValue.split(";");
 
-        return new IntegerRangeData(
-            name,
-            label,
-            Integer.valueOf(minmax[0]),
-            Integer.valueOf(minmax[1]));
+        return new IntegerRangeData(name, label, Integer.valueOf(minmax[0]), Integer.valueOf(minmax[1]));
     }
 
-
     /**
      * This method creates a new instance of DefaultData which has a type
      * "integerarray" set.
      *
-     * @param ele The Data element.
-     * @param name The name of the Data instance.
+     * @param ele
+     *            The Data element.
+     * @param name
+     *            The name of the Data instance.
      *
      * @return an instance of IntegerArrayData.
      */
-    protected static Data createIntegerArrayData(
-        Element ele,
-        String name,
-        String label
-    ) {
-        IntDataItem[] items    = extractIntDataItems(ele);
+    protected static Data createIntegerArrayData(final Element ele, final String name, final String label) {
+        final IntDataItem[] items = extractIntDataItems(ele);
         return new IntegerArrayData(name, label, items);
     }
 
-
     /**
      * This method creates a new instance of DefaultData which has a type
      * "doublearray" set.
      *
-     * @param ele The Data element.
-     * @param name The name of the Data instance.
+     * @param ele
+     *            The Data element.
+     * @param name
+     *            The name of the Data instance.
      *
      * @return an instance of DoubleArrayData.
      */
-    protected static Data createDoubleArrayData(
-        Element ele,
-        String name,
-        String label
-    ) {
-        DataItem[] items    = extractDataItems(ele);
-        String     rawValue = items[0].getStringValue();
+    protected static Data createDoubleArrayData(final Element ele, final String name, final String label) {
+        final DataItem[] items = extractDataItems(ele);
+        final String rawValue = items[0].getStringValue();
 
-        String[] values  = rawValue.split(";");
-        double[] doubles = new double[values.length];
+        final String[] values = rawValue.split(";");
+        final double[] doubles = new double[values.length];
 
         for (int i = 0; i < values.length; i++) {
             try {
                 doubles[i] = Double.valueOf(values[i]);
             }
-            catch (NumberFormatException nfe) {
+            catch (final NumberFormatException nfe) {
                 log.warn("Error while parsing DoubleArrayData: " + nfe);
             }
         }
@@ -354,37 +308,33 @@
         return new DoubleArrayData(name, label, doubles);
     }
 
-
     /**
      * This method extracts the art:item elements placed under <i>elements</i>.
      *
-     * @param element A data node that contains items.
+     * @param element
+     *            A data node that contains items.
      *
      * @return a list of DataItems.
      */
-    protected static DataItem[] extractDataItems(Element element) {
-        NodeList itemList = (NodeList) XMLUtils.xpath(
-            element,
-            "art:item",
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
+    protected static DataItem[] extractDataItems(final Element element) {
+        final NodeList itemList = (NodeList) XMLUtils.xpath(element, "art:item", XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE);
 
         if (itemList == null || itemList.getLength() == 0) {
             log.debug("No data items found.");
             return null;
         }
 
-        int count = itemList.getLength();
+        final int count = itemList.getLength();
 
-        DataItem[] items = new DataItem[count];
+        final DataItem[] items = new DataItem[count];
 
         log.debug("There are " + count + " data items in element.");
 
         for (int i = 0; i < count; i++) {
-            Element tmp = (Element) itemList.item(i);
+            final Element tmp = (Element) itemList.item(i);
 
-            String value = tmp.getAttributeNS(NS_URI, "value");
-            String label = tmp.getAttributeNS(NS_URI, "label");
+            final String value = tmp.getAttributeNS(NS_URI, "value");
+            final String label = tmp.getAttributeNS(NS_URI, "label");
 
             log.debug("Found data item:");
             log.debug("   label: " + label);
@@ -396,71 +346,61 @@
         return items;
     }
 
-
     /**
      * This method extracts the art:item elements placed under <i>elements</i>.
      *
-     * @param element A data node that contains items.
+     * @param element
+     *            A data node that contains items.
      *
      * @return a list of DataItems.
      */
-    protected static IntDataItem[] extractIntDataItems(Element element) {
-        NodeList itemList = (NodeList) XMLUtils.xpath(
-            element,
-            "art:item",
-            XPathConstants.NODESET,
-            ArtifactNamespaceContext.INSTANCE);
+    protected static IntDataItem[] extractIntDataItems(final Element element) {
+        final NodeList itemList = (NodeList) XMLUtils.xpath(element, "art:item", XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE);
 
         if (itemList == null || itemList.getLength() == 0) {
             log.debug("No old data items found.");
             return null;
         }
 
-        int count = itemList.getLength();
-
-        IntDataItem[] items = new IntDataItem[count];
-
-         for (int i = 0; i < count; i++) {
-             Element tmp = (Element) itemList.item(i);
+        final int count = itemList.getLength();
 
-             String value = tmp.getAttributeNS(NS_URI, "value");
-             String label = tmp.getAttributeNS(NS_URI, "label");
+        final IntDataItem[] items = new IntDataItem[count];
 
-             try {
-                 int data = Integer.parseInt(value);
-                 items[i] = new IntDataItem(label, label, data);
-             }
-             catch(NumberFormatException nfe) {
-                 log.debug(nfe, nfe);
-             }
-         }
-         return items;
+        for (int i = 0; i < count; i++) {
+            final Element tmp = (Element) itemList.item(i);
+
+            final String value = tmp.getAttributeNS(NS_URI, "value");
+            final String label = tmp.getAttributeNS(NS_URI, "label");
+
+            try {
+                final int data = Integer.parseInt(value);
+                items[i] = new IntDataItem(label, label, data);
+            }
+            catch (final NumberFormatException nfe) {
+                log.debug(nfe, nfe);
+            }
+        }
+        return items;
     }
 
     /**
      * This method creates a new instance of LongRangeData which has a type
      * "longrange" set.
      *
-     * @param ele The Data element.
-     * @param name The name of the Data instance.
+     * @param ele
+     *            The Data element.
+     * @param name
+     *            The name of the Data instance.
      *
      * @return an instance of IntegerRangeData.
      */
-    protected static Data createLongRangeData(
-        Element ele,
-        String name,
-        String label
-    ) {
-        DataItem[] items    = extractDataItems(ele);
-        String     rawValue = items[0].getStringValue();
+    protected static Data createLongRangeData(final Element ele, final String name, final String label) {
+        final DataItem[] items = extractDataItems(ele);
+        final String rawValue = items[0].getStringValue();
 
-        String[] minmax = rawValue.split(";");
+        final String[] minmax = rawValue.split(";");
 
-        return new LongRangeData(
-            name,
-            label,
-            Long.valueOf(minmax[0]),
-            Long.valueOf(minmax[1]));
+        return new LongRangeData(name, label, Long.valueOf(minmax[0]), Long.valueOf(minmax[1]));
     }
 
 }
--- a/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/MultiAttributeData.java	Thu May 17 13:06:12 2018 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/MultiAttributeData.java	Fri May 18 17:26:26 2018 +0200
@@ -10,10 +10,9 @@
 
 import java.util.Map;
 
+public class MultiAttributeData implements Data {
 
-public class MultiAttributeData
-implements Data
-{
+    private static final long serialVersionUID = 1L;
 
     public static final String TYPE = "multiattribute";
 
@@ -24,24 +23,18 @@
 
     public DataItem[] opts;
 
-
     public MultiAttributeData() {
     }
 
-
-    public MultiAttributeData(
-        String                           label,
-        String                           desc,
-        DataItem[]                       opts,
-        Map<String, Map<String, String>> meta
-    ) {
-        this.label       = label;
+    public MultiAttributeData(final String label, final String desc, final DataItem[] opts, final Map<String, Map<String, String>> meta) {
+        this.label = label;
         this.description = desc;
-        this.opts        = opts;
+        this.opts = opts;
+        this.meta = meta;
     }
 
     public Map<String, Map<String, String>> getMeta() {
-        return meta;
+        return this.meta;
     }
 
     /**
@@ -49,62 +42,63 @@
      *
      * @return the label.
      */
+    @Override
     public String getLabel() {
-        return label;
+        return this.label;
     }
 
-
     /**
      * Returns the description of the item.
      *
      * @return the description.
      */
+    @Override
     public String getDescription() {
-        return description;
+        return this.description;
     }
 
-
     /**
      * Returns the type of the item.
      *
      * @return the type.
      */
+    @Override
     public String getType() {
         return TYPE;
     }
 
-
     /**
      * Returns the data items which represent the allowed options for this Data.
      *
      * @return the allowed options as DataItem array.
      */
+    @Override
     public DataItem[] getItems() {
-        return opts;
+        return this.opts;
     }
 
-
     /**
      * @return always null.
      */
+    @Override
     public DataItem getDefault() {
         return null;
     }
 
-
     /**
      * Returns the values as colon separated string.
      *
      * @return colon separated string.
      */
+    @Override
     public String getStringValue() {
         String data = "";
         boolean first = true;
-        for (int i = 0; i < opts.length; i++) {
+        for (final DataItem opt : this.opts) {
             if (!first) {
                 data += ";";
             }
-            data += opts[i].getStringValue();
+            data += opt.getStringValue();
             first = false;
         }
         return data;

http://dive4elements.wald.intevation.org