changeset 8999:e3b3ce32c825

Work on uinfo
author gernotbelger
date Thu, 12 Apr 2018 19:15:42 +0200
parents c38098b15427
children 50cc99579a46
files artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCalculationResult.java artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCalculationResults.java artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCommonExporter.java artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractResultType.java artifacts/src/main/java/org/dive4elements/river/artifacts/common/GeneralResultType.java artifacts/src/main/java/org/dive4elements/river/artifacts/common/I18NStrings.java artifacts/src/main/java/org/dive4elements/river/artifacts/common/IResultType.java artifacts/src/main/java/org/dive4elements/river/artifacts/common/JRReportSaxParserFactory.java artifacts/src/main/java/org/dive4elements/river/artifacts/common/ResultRow.java
diffstat 9 files changed, 755 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/AbstractCalculationResult.java	Thu Apr 12 19:15:42 2018 +0200
@@ -0,0 +1,85 @@
+/** 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.common;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.dive4elements.river.artifacts.common.IResultType;
+import gnu.trove.TDoubleArrayList;
+
+/**
+ * @author Gernot Belger
+ */
+public abstract class AbstractCalculationResult implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    protected final Collection<ResultRow> rows;
+
+    private final String label;
+
+ 
+
+    public AbstractCalculationResult(final String label,  final Collection<ResultRow> rows) {
+        this.label = label;  
+        this.rows = new ArrayList<>(rows);
+    }
+
+    public final String getLabel() {
+        return this.label;
+    }
+ 
+
+    public boolean isEmpty() {
+        return this.rows.isEmpty();
+    }
+
+    public final void addRow(final ResultRow resultRow) {
+        this.rows.add(resultRow);
+    }
+
+    public final Collection<ResultRow> getRows() {
+        return Collections.unmodifiableCollection(this.rows);
+    }
+
+    public final double[][] getStationPoints(final IResultType type) { //gehört die Methode hier rein? oder in erbende Klassen?
+
+        final TDoubleArrayList xPoints = new TDoubleArrayList(this.rows.size());
+        final TDoubleArrayList yPoints = new TDoubleArrayList(this.rows.size());
+
+        for (final ResultRow row : this.rows) {
+
+            final double station = row.getDoubleValue(GeneralResultType.station); //TODO: move "station" (and others) to common
+            final double value = row.getDoubleValue(type);
+
+            xPoints.add(station);
+            yPoints.add(value);
+        }
+
+        return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() };
+    }
+
+    protected final <TYPE> List<TYPE> getValues(final IResultType type) {
+
+        final List<TYPE> values = new ArrayList<>();
+
+        for (final ResultRow row : this.rows) {
+            @SuppressWarnings("unchecked")
+            final TYPE value = (TYPE) row.getValue(type);
+            values.add(value);
+        }
+
+        return values;
+    }
+}
\ 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/common/AbstractCalculationResults.java	Thu Apr 12 19:15:42 2018 +0200
@@ -0,0 +1,77 @@
+/** 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.common;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang.math.DoubleRange;
+import org.dive4elements.river.artifacts.model.Calculation;
+import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
+
+/**
+ * @author Gernot Belger
+ */
+public abstract class AbstractCalculationResults<RESULT extends AbstractCalculationResult> implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private final List<RESULT> results = new ArrayList<>();
+
+    private final String calcModeLabel;
+
+    private final String user;
+
+    private final RiverInfo river;
+
+    private final DoubleRange calcRange;
+
+    public AbstractCalculationResults(final String calcModeLabel, final String user, final RiverInfo river, final DoubleRange calcRange) {
+        this.calcModeLabel = calcModeLabel;
+        this.user = user;
+        this.river = river;
+        this.calcRange = calcRange;
+    }
+
+    public String getCalcModeLabel() {
+        return this.calcModeLabel;
+    }
+
+    public String getUser() {
+        return this.user;
+    }
+
+    public RiverInfo getRiver() {
+        return this.river;
+    }
+
+    public DoubleRange getCalcRange() {
+        return this.calcRange;
+    }
+
+    public void addResult(final RESULT result, final Calculation problems) {
+        /* we assume error reporting was already done in this case */
+        if (result == null)
+            return;
+
+        if (result.isEmpty()) {
+            problems.addProblem("abstractsinfocalculationresults.emptyResult", result.getLabel());
+            return;
+        }
+
+        this.results.add(result);
+    }
+
+    public List<RESULT> getResults() {
+        return Collections.unmodifiableList(this.results);
+    }
+}
\ 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/common/AbstractCommonExporter.java	Thu Apr 12 19:15:42 2018 +0200
@@ -0,0 +1,240 @@
+/** 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.common;
+
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.artifacts.common.utils.Config;
+import org.dive4elements.river.artifacts.model.CalculationResult;
+import org.dive4elements.river.artifacts.resources.Resources;
+import org.dive4elements.river.artifacts.sinfo.util.MetaAndTableJRDataSource;
+import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
+import org.dive4elements.river.exports.AbstractExporter;
+
+import au.com.bytecode.opencsv.CSVWriter;
+import net.sf.jasperreports.engine.JRDataSource;
+import net.sf.jasperreports.engine.JRElement;
+import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JRPrintPage;
+import net.sf.jasperreports.engine.JasperCompileManager;
+import net.sf.jasperreports.engine.JasperExportManager;
+import net.sf.jasperreports.engine.JasperFillManager;
+import net.sf.jasperreports.engine.JasperPrint;
+import net.sf.jasperreports.engine.JasperReport;
+import net.sf.jasperreports.engine.design.JasperDesign;
+import net.sf.jasperreports.engine.util.JRProperties;
+import net.sf.jasperreports.engine.xml.JRSaxParserFactory;
+import net.sf.jasperreports.engine.xml.JRXmlLoader;
+
+/**
+ * @author Gernot Belger
+ */
+public abstract class AbstractCommonExporter<RESULT extends AbstractCalculationResult, RESULTS extends AbstractCalculationResults<RESULT>> extends AbstractExporter {
+
+    /** The storage that contains the current calculation result. */
+    protected static enum ExportMode {
+        pdf, csv
+    }
+
+    /** The log used in this exporter. */
+    protected abstract Logger getLog();
+
+    protected RESULTS data = null;
+
+    public RESULTS getData() {
+        return this.data;
+    }
+
+    @Override
+    protected void addData(final Object d) {
+        /* reset */
+        this.data = null;
+
+        if (d instanceof CalculationResult) {
+
+            final Object dat = ((CalculationResult) d).getData();
+            if (dat != null) {
+                @SuppressWarnings("unchecked")
+                final RESULTS result = (RESULTS) dat;
+                this.data = result;
+            }
+        }
+    }
+
+    /**
+     * Formats header with unit and label: msg [unit] (label)
+     */
+    protected String msgUnitLabel(final String key, final String unit, final String label) {
+        final String msg = msg(key);
+        return String.format("%s [%s] (%s)", msg, unit, label);
+    }
+
+    @Override
+    protected void writeCSVData(final CSVWriter writer) {
+        getLog().info("writeCSVData");
+
+        /* fetch calculation results */
+        final RESULTS results = this.data;
+
+        /* write as csv */
+        writeCSVGlobalMetadata(writer, results);
+        writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
+        final RiverInfo river = results.getRiver();
+        // FIXME :with comment if not first result
+        writeCSVHeader(writer, results, river);
+        writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
+
+        for (final RESULT result : results.getResults()) {
+            writeCSVResult(writer, results, result);
+            writer.writeNext(new String[] { "" }); // break line HERE after each resultset
+        }
+
+    }
+
+    protected abstract void writeCSVHeader(final CSVWriter writer, final RESULTS results, final RiverInfo river);
+
+    /**
+     * Add metadata that is once written to the top of the file.
+     */
+    protected abstract void writeCSVGlobalMetadata(final CSVWriter writer, final RESULTS results);
+
+    protected void writeCSVMetaEntry(final CSVWriter writer, final String message, final Object... messageArgs) {
+
+        final CallMeta meta = this.context.getMeta();
+
+        writer.writeNext(new String[] { Resources.getMsg(meta, message, message, messageArgs) });
+    }
+
+    private void writeCSVResult(final CSVWriter writer, final RESULTS results, final RESULT result) {
+
+        writeCSVResultMetadata(writer, results, result);
+        writer.writeNext(new String[] { "" }); // break line HERE to avoid redundance
+
+        // final RiverInfo river = results.getRiver();
+        //
+        // writeCSVHeader(writer, results, river);
+        /* now the value rows */
+        final Collection<ResultRow> rows = result.getRows(); // war mal SInfoResultRow
+        for (final ResultRow row : rows) {
+            writeCSVRow(writer, results, result, row);
+        }
+    }
+
+    /**
+     * Add metadata that is written once per result set.
+     */
+    protected abstract void writeCSVResultMetadata(CSVWriter writer, RESULTS results, RESULT result);
+
+    protected void writeCSVRow(final CSVWriter writer, final RESULTS results, final RESULT result, final ResultRow row) {
+        getLog().debug("writeCSVFlowDepthRow");
+
+        final String[] formattedRow = formatCSVRow(results, row);
+        writer.writeNext(formattedRow);
+    }
+
+    protected final String[] formatCSVRow(final RESULTS results, final ResultRow row) {
+        return formatRow(results, row, ExportMode.csv);
+    }
+
+    // protected abstract void tweakDesign()
+
+    @Override
+    protected void writePDF(final OutputStream outStream) {
+        getLog().debug("write PDF");
+
+        final JRDataSource source = createJRData();
+        final JRDataSource source2 = createJRData();
+
+        final String confPath = Config.getConfigDirectory().toString();
+
+        // FIXME: distinguish between with and without tkh: we need two jasper reports!
+
+        final Map<String, Object> parameters = new HashMap<>();
+        parameters.put("ReportTitle", "Exported Data");
+
+        try {
+
+            // JRProperties.setProperty(JRProperties.COMPILER_XML_VALIDATION, false);
+            JRProperties.setProperty(JRSaxParserFactory.PROPERTY_REPORT_PARSER_FACTORY, JRReportSaxParserFactory.class.getName());
+
+            final String jasperPath = confPath + getJasperFile();
+            final JasperDesign test = JRXmlLoader.load(jasperPath);
+
+            final JRElement element = test.getColumnHeader().getElementByKey("TEST");
+            // element.setWidth(200);
+
+            final JasperReport compiled = JasperCompileManager.compileReport(test);
+
+            final JasperPrint print = JasperFillManager.fillReport(compiled, parameters, source);
+            // JasperExportManager.exportReportToPdfStream(print, outStream);
+
+            final JasperPrint print2 = JasperFillManager.fillReport(compiled, parameters, source2);
+
+            final List<JRPrintPage> pages = print2.getPages();
+            for (final JRPrintPage page : pages)
+                print.addPage(page);
+
+            JasperExportManager.exportReportToPdfStream(print, outStream);
+        }
+        catch (final JRException je) {
+            getLog().warn("Error generating PDF Report!", je);
+        }
+    }
+
+    protected abstract String getJasperFile();
+
+    private JRDataSource createJRData() {
+
+        /* fetch calculation results */
+        final RESULTS results = this.data;
+
+        final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
+
+        addJRMetaData(source, results);
+
+        for (final RESULT result : results.getResults()) {
+            addJRTableData(source, results, result);
+        }
+
+        return source;
+    }
+
+    protected abstract void addJRMetaData(final MetaAndTableJRDataSource source, final RESULTS results);
+
+    protected void addJRTableData(final MetaAndTableJRDataSource source, final RESULTS results, final RESULT result) {
+
+        final Collection<ResultRow> rows = result.getRows();
+
+        for (final ResultRow row : rows) {
+
+            final String[] formattedRow = formatPDFRow(results, row);
+            source.addData(formattedRow);
+        }
+    }
+
+    protected abstract String[] formatRow(RESULTS results, ResultRow row, ExportMode mode);
+
+    protected final String[] formatPDFRow(final RESULTS results, final ResultRow row) {
+        // @Override
+        // protected String[] formatPDFRow(final FlowDepthDevelopmentCalculationResults results, final ResultRow row) {
+        return formatRow(results, row, ExportMode.pdf);
+        // }
+    }
+
+    protected abstract void writeCSVGlobalMetadataDefaults(final CSVWriter writer, final RESULTS results);
+
+    protected abstract void addJRMetaDataDefaults(final MetaAndTableJRDataSource source, final RESULTS results);
+}
\ 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/common/AbstractResultType.java	Thu Apr 12 19:15:42 2018 +0200
@@ -0,0 +1,104 @@
+/** 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.common;
+
+import java.text.NumberFormat;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.artifacts.CallMeta;
+import org.dive4elements.river.artifacts.resources.Resources;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+public abstract class AbstractResultType implements IResultType {
+
+    /* Cache for formatters because Formatter will always create new formats (which is very expensive) */
+    private final Map<Locale, NumberFormat> formatters = new HashMap<>();
+
+    private final String unit;
+
+    private final String csvHeader;
+
+    private final String pdfHeader;
+
+    protected AbstractResultType(final String unit, final String csvHeader, final String pdfHeader) {
+        this.unit = unit;
+        this.csvHeader = csvHeader;
+        this.pdfHeader = pdfHeader;
+
+    }
+
+    @Override
+    public abstract String exportValue(final CallContext context, final Object value);
+
+    protected final String exportStringValue(final Object value) {
+
+        if (value == null)
+            return StringUtils.EMPTY;
+
+        if (!(value instanceof String))
+            throw new IllegalStateException();
+
+        return (String) value;
+    }
+
+    @Override
+    public final double asDouble(final Object value) {
+        if (value == null)
+            return Double.NaN;
+
+        if (!(value instanceof Number))
+            throw new IllegalStateException();
+
+        final Number number = (Number) value;
+        return number.doubleValue();
+    }
+
+    protected final String exportDoubleValue(final CallContext context, final double value) {
+        if (Double.isNaN(value))
+            return StringUtils.EMPTY;
+
+        final NumberFormat formatter = getFormatter(context);
+        return formatter.format(value);
+    }
+
+    private NumberFormat getFormatter(final CallContext context) {
+        final CallMeta meta = context.getMeta();
+        final Locale locale = Resources.getLocale(meta);
+
+        if (!this.formatters.containsKey(locale))
+            this.formatters.put(locale, createFormatter(context));
+
+        return this.formatters.get(locale);
+    }
+
+    protected abstract NumberFormat createFormatter(CallContext context);
+
+    public final String getCsvHeader() {
+        return this.csvHeader;
+    }
+
+    public final String getCsvHeader(final CallMeta meta) {
+        return Resources.getMsg(meta, this.csvHeader, this.csvHeader);
+    }
+
+    public final String getPdfHeader(final CallMeta meta) {
+        return Resources.getMsg(meta, this.pdfHeader, this.pdfHeader);
+    }
+
+    public final String getUnit() {
+        return this.unit;
+    }
+}
\ 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/common/GeneralResultType.java	Thu Apr 12 19:15:42 2018 +0200
@@ -0,0 +1,45 @@
+/** 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.common;
+
+import java.text.NumberFormat;
+
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.utils.Formatter;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public abstract class GeneralResultType extends AbstractResultType {
+    
+    public static final GeneralResultType station =   new GeneralResultType(I18NStrings.UNIT_KM, I18NStrings.CSV_KM_HEADER) {
+        @Override
+        public String exportValue(final CallContext context, final Object value) {
+            final double doubleValue = asDouble(value);
+            return exportDoubleValue(context, doubleValue);
+        }
+
+        @Override
+        protected NumberFormat createFormatter(final CallContext context) {
+            return Formatter.getWaterlevelKM(context);
+        }
+    };
+    
+    
+    private  GeneralResultType(String unit, String csvHeader) {
+        
+        super(unit, csvHeader, csvHeader);
+    }
+    private GeneralResultType(String unit, String csvHeader, String pdfHeader) {
+        super(unit, csvHeader, pdfHeader);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/I18NStrings.java	Thu Apr 12 19:15:42 2018 +0200
@@ -0,0 +1,64 @@
+/** 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.common;
+
+/**
+ * @author Domenico Nardi Tironi
+ *
+ */
+public interface I18NStrings {
+    //////////// GENERIC TYPES + UNITS///////////////////////////////////////////////////////////////////////////////
+
+    // TODO: remove "sinfo" for these labels in messages.txt + de.messages.txt
+
+    String CSV_KM_HEADER = "sinfo.export.flow_depth.csv.header.km";
+
+    String CSV_META_HEADER_RESULT_LABEL = "sinfo.export.flow_depth.csv.meta.header.result.label";
+
+    String CSV_META_VERSION_LABEL = "sinfo.export.flow_depth.csv.meta.version.label";
+
+    String CSV_META_USER_LABEL = "sinfo.export.flow_depth.csv.meta.user.label";
+
+    String CSV_META_CREATION_LABEL = "sinfo.export.flow_depth.csv.meta.creation.label";
+
+    String CSV_META_RIVER_LABEL = "sinfo.export.flow_depth.csv.meta.river.label";
+
+    String CSV_META_RANGE_LABEL = "sinfo.export.flow_depth.csv.meta.range.label";
+
+    String CSV_META_HEADER_RESULT = "sinfo.export.flow_depth.csv.meta.header.result";
+
+    String CSV_META_VERSION = "sinfo.export.flow_depth.csv.meta.version";
+
+    String CSV_META_USER = "sinfo.export.flow_depth.csv.meta.user";
+
+    String CSV_META_CREATION = "sinfo.export.flow_depth.csv.meta.creation";
+
+    String CSV_META_RIVER = "sinfo.export.flow_depth.csv.meta.river";
+
+    String CSV_META_RANGE = "sinfo.export.flow_depth.csv.meta.range";
+
+    String CSV_META_HEIGHT_UNIT_RIVER = "sinfo.export.flow_depth.csv.meta.height_unit.river"; // move to child?
+
+    /// sonstiges:
+
+    // Einheiten:
+
+    String UNIT_NONE = "-";
+
+    String UNIT_M = "m";
+
+    String UNIT_KM = "km";
+
+    String UNIT_CM = "cm";
+
+    String UNIT_CM_A = "cm/a";
+
+    String UNIT_CUBIC_M = "m³/s";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/common/IResultType.java	Thu Apr 12 19:15:42 2018 +0200
@@ -0,0 +1,24 @@
+/** 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.common;
+
+import java.io.Serializable;
+
+import org.dive4elements.artifacts.CallContext;
+
+/**
+ * @author Domenico Nardi Tironi
+ */
+public interface IResultType extends Serializable {
+
+    String exportValue(final CallContext context, final Object value);
+
+    double asDouble(final Object value);
+}
\ 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/common/JRReportSaxParserFactory.java	Thu Apr 12 19:15:42 2018 +0200
@@ -0,0 +1,59 @@
+/** 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.common;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import net.sf.jasperreports.engine.component.ComponentsBundle;
+import net.sf.jasperreports.engine.component.ComponentsEnvironment;
+import net.sf.jasperreports.engine.component.ComponentsXmlParser;
+import net.sf.jasperreports.engine.xml.BaseSaxParserFactory;
+import net.sf.jasperreports.engine.xml.JRXmlConstants;
+
+/**
+ * Own sax parser factory, because:
+ * - we do not want xml validation (we know it's good)
+ * - xerxes sax parser complains about two schemas with same namespace...
+ * 
+ * @author Domenico Nardi Tironi
+ */
+public class JRReportSaxParserFactory extends BaseSaxParserFactory {
+
+    @Override
+    protected boolean isValidating() {
+        return false;
+    }
+
+    @Override
+    protected List<String> getSchemaLocations() {
+        final List<String> schemas = new ArrayList<>();
+
+        schemas.add(getResourceURI(JRXmlConstants.JASPERREPORT_XSD_RESOURCE));
+        // schemas.add(getResourceURI(JRXmlConstants.JASPERREPORT_XSD_DTD_COMPAT_RESOURCE));
+
+        final Collection<ComponentsBundle> components = ComponentsEnvironment.getComponentBundles();
+        for (final ComponentsBundle componentManager : components) {
+            final ComponentsXmlParser xmlParser = componentManager.getXmlParser();
+
+            String schemaURI;
+            final String schemaResource = xmlParser.getInternalSchemaResource();
+            if (schemaResource != null) {
+                schemaURI = getResourceURI(schemaResource);
+            } else {
+                schemaURI = xmlParser.getPublicSchemaLocation();
+            }
+
+            schemas.add(schemaURI);
+        }
+        return schemas;
+    }
+}
\ 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/common/ResultRow.java	Thu Apr 12 19:15:42 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.common;
+
+import java.io.Serializable; 
+import java.util.HashMap;
+import java.util.Map;
+
+import org.dive4elements.artifacts.CallContext;
+import org.dive4elements.river.artifacts.common.IResultType;
+
+/**
+ * Generic container for results that come in rows.
+ *
+ * @author Gernot Belger
+ */
+public class ResultRow implements Serializable {
+    protected static final long serialVersionUID = 1L; //TODO: Make private (wenn SInfoResultRow gelöscht ist
+
+    private final Map<IResultType, Object> values = new HashMap<IResultType, Object>();
+
+    public static ResultRow create() {
+        return new ResultRow();
+    }
+
+    protected ResultRow() {
+    }
+
+    public ResultRow putValue(final IResultType type, final Object value) {
+
+        this.values.put(type, value);
+
+        /* chain me */
+        return this;
+    }
+
+    public String exportValue(final CallContext context, final IResultType type) {
+        final Object value = this.values.get(type);
+        return type.exportValue(context, value);
+    }
+
+    public double getDoubleValue(final IResultType type) {
+        final Object value = this.values.get(type);
+        return type.asDouble(value);
+    }
+
+    public Object getValue(final IResultType type) {
+        return this.values.get(type);
+    }
+}
\ No newline at end of file

http://dive4elements.wald.intevation.org