view artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadFactory.java @ 7184:73d7886fa59e

SedimentLoadFactory: Fix query, added comment about correctness of fraction_type -> measurementstation assignment.
author Felix Wolfsteller <felix.wolfsteller@intevation.de>
date Fri, 27 Sep 2013 14:35:42 +0200
parents 805021c04861
children 963b8bd54a63
line wrap: on
line source
/* 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.artifacts.model.minfo;

import gnu.trove.TDoubleArrayList;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TreeMap;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

import org.apache.log4j.Logger;
import org.dive4elements.river.artifacts.cache.CacheFactory;
import org.dive4elements.river.artifacts.model.Range;
import org.dive4elements.river.artifacts.model.RiverFactory;
import org.dive4elements.river.artifacts.model.StaticSedimentLoadCacheKey;
import org.dive4elements.river.backend.SessionHolder;
import org.dive4elements.river.model.MeasurementStation;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.type.StandardBasicTypes;


/** Pull Sediment Loads out of db. */
public class SedimentLoadFactory
{
    /** Private logger to use here. */
    private static Logger log = Logger.getLogger(SedimentLoadFactory.class);

    // Cache name/keys
    public static final String LOADS_CACHE_NAME = "sedimentloads";
    public static final String LOAD_DATA_CACHE_NAME = "sedimentload-data";

    /** Query to get description and start year of single type
     * sediment_yields. */
    public static final String SQL_SELECT_SINGLES =
        "SELECT DISTINCT " +
        "       sy.description AS description, " +
        "       ti.start_time AS year " +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "   WHERE   r.name = :name " +
        "       AND ti.stop_time IS NULL " +
        "       AND syv.station BETWEEN :startKm AND :endKm";

    /** Query to get description, name and time range for official
     * epoch-type sediment yields. */
    public static final String SQL_SELECT_OFFEPOCHS =
        "SELECT DISTINCT " +
        "       ti.start_time AS startYear, " +
        "       ti.stop_time AS end " +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "   WHERE   r.name = :name " +
        "       AND ti.stop_time IS NOT NULL " +
        "       AND syv.station BETWEEN :startKm AND :endKm " +
        "       AND sy.kind = 1";

    /** Query to get description, name and time range for epoch-type
     * sediment yields. */
    public static final String SQL_SELECT_EPOCHS =
        "SELECT DISTINCT " +
        "       sy.description AS description, " +
        "       ti.start_time AS startYear, " +
        "       ti.stop_time AS end, " +
        "       u.name AS unit" +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "       JOIN units u ON u.id = sy.unit_id " +
        "   WHERE   r.name = :name " +
        "       AND ti.stop_time IS NOT NULL " +
        "       AND syv.station BETWEEN :startKm AND :endKm";

    public static final String SQL_SELECT_SINGLES_DATA_BY_ID =
        "SELECT" +
        "       sy.description AS description, " +
        "       syv.value AS load, " +
        "       syv.station AS km, " +
        "       u.name AS unit, " +
        "       gf.name AS fraction " +
        "   FROM     sediment_yield sy " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN units u ON u.id = sy.unit_id" +
        "       JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " +
        "   WHERE   sy.id = :id" +
        "   ORDER BY syv.station";

    public static final String SQL_SELECT_SINGLES_DATA =
        "SELECT" +
        "       sy.description AS description, " +
        "       ti.start_time AS year, " +
        "       syv.value AS load, " +
        "       syv.station AS km, " +
        "       u.name AS unit " +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " +
        "       JOIN units u ON u.id = sy.unit_id" +
        "   WHERE   r.name = :name " +
        "       AND ti.start_time BETWEEN :begin AND :end " +
        "       AND ti.stop_time IS NULL " +
        "       AND gf.name = :grain " +
        "       AND syv.station BETWEEN :startKm AND :endKm " +
        "   ORDER BY syv.station";

    public static final String SQL_SELECT_UNKNOWN_DATA =
        "SELECT" +
        "       sy.description AS description, " +
        "       ti.start_time AS startYear, " +
        "       ti.stop_time AS end, " +
        "       syv.value AS load, " +
        "       syv.station AS km, " +
        "       u.name AS unit " +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " +
        "       JOIN units u ON u.id = sy.unit_id" +
        "   WHERE   r.name = :name " +
        "       AND sy.description = :descr " +
        "       AND gf.name = 'unknown' " +
        "   ORDER BY syv.station";

    public static final String SQL_SELECT_UNKNOWN =
        "SELECT DISTINCT " +
        "    sy.description AS description, " +
        "    ti.start_time AS startYear, " +
        "    ti.stop_time AS end " +
        "FROM sediment_yield sy " +
        "    JOIN rivers r ON sy.river_id = r.id " +
        "    JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "    JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " +
        "    JOIN units u ON sy.unit_id = u.id " +
        "WHERE r.name = :river " +
        "    AND gf.name = 'unknown' " +
        "    AND sy.kind = :type " +
        "    AND u.name = :unit";

    public static final String SQL_SELECT_EPOCHS_DATA =
        "SELECT" +
        "       sy.description AS description, " +
        "       ti.start_time AS startYear, " +
        "       syv.value AS load, " +
        "       syv.station AS km," +
        "       ti.stop_time AS endYear, " +
        "       u.name AS unit" +
        "   FROM     sediment_yield sy " +
        "       JOIN rivers r ON sy.river_id = r.id " +
        "       JOIN time_intervals ti ON sy.time_interval_id = ti.id " +
        "       JOIN sediment_yield_values syv ON sy.id = syv.sediment_yield_id " +
        "       JOIN grain_fraction gf ON sy.grain_fraction_id = gf.id " +
        "       JOIN units u ON u.id = sy.unit_id " +
        "   WHERE   r.name = :name " +
        "       AND ti.start_time BETWEEN :sbegin AND :send " +
        "       AND ti.stop_time BETWEEN :ebegin AND :eend " +
        "       AND gf.name = :grain " +
        "       AND syv.station BETWEEN :startKm AND :endKm " +
        "   ORDER BY syv.station";

    private SedimentLoadFactory() {
    }

    /**
     * @param river name of river.
     * @param type
     */
    public static SedimentLoad[] getLoads(
        String river,
        String type,
        double startKm,
        double endKm
    ) {
        log.debug("SedimentLoadFactory.getLoads");
        Cache cache = CacheFactory.getCache(LOADS_CACHE_NAME);

        if (cache == null) {
            log.debug("Cache not configured.");
            return getSedimentLoadsUncached(river, type, startKm, endKm);
        }

        StaticSedimentLoadCacheKey key =
            new StaticSedimentLoadCacheKey(river, startKm, endKm, 0, 0);

        Element element = cache.get(key);

        if (element != null) {
            log.debug("SedimentLoad found in cache");
            return (SedimentLoad[])element.getValue();
        }

        SedimentLoad[] values =
            getSedimentLoadsUncached(river, type, startKm, endKm);

        if (values != null && key != null) {
            log.debug("Store static sediment load values in cache.");
            element = new Element(key, values);
            cache.put(element);
        }
        return values;
    }

    /**
     * Get a sedimentLoad filled with data from db (or cache).
     * @param type "epoch", "off_epoch" or "single"
     * @return A Sedimentload filled with values from db or cache.
     */
    public static SedimentLoad getLoadWithData(
        String river,
        String type,
        double startKm,
        double endKm,
        int syear,
        int eyear
    ) {
        log.debug("SedimentLoadFactory.getLoadWithData");
        Cache cache = CacheFactory.getCache(LOAD_DATA_CACHE_NAME);

        if (cache == null) {
            log.debug("Cache not configured.");
            return getSedimentLoadWithDataUncached(
                river,
                type,
                startKm,
                endKm,
                syear,
                eyear);
        }

        StaticSedimentLoadCacheKey key =
            new StaticSedimentLoadCacheKey(river, startKm, endKm, syear, eyear);

        Element element = cache.get(key);

        if (element != null) {
            log.debug("SedimentLoad found in cache");
            return (SedimentLoad)element.getValue();
        }

        SedimentLoad values = getSedimentLoadWithDataUncached(
            river,
            type,
            startKm,
            endKm,
            syear,
            eyear);

        if (values != null && key != null) {
            log.debug("Store sediment loads in cache.");
            element = new Element(key, values);
            cache.put(element);
        }
        return values;
    }

    /**
     * Get sediment loads from db.
     * @param river the river
     * @param type the sediment load type (year or epoch)
     * @return according sediment loads.
     */
    public static SedimentLoad[] getSedimentLoadsUncached(
        String river,
        String type,
        double startKm,
        double endKm
    ) {
        log.debug("SedimentLoadFactory.getSedimentLoadsUncached");

        Session session = SessionHolder.HOLDER.get();
        SQLQuery sqlQuery = null;

        if (type.equals("single")) {
            sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLES)
                .addScalar("description", StandardBasicTypes.STRING)
                .addScalar("year", StandardBasicTypes.DATE);
            sqlQuery.setString("name", river);
            sqlQuery.setDouble("startKm", startKm);
            sqlQuery.setDouble("endKm", endKm);
            List<Object []> results = sqlQuery.list();
            SedimentLoad[] loads = new SedimentLoad[results.size()];
            for (int i = 0; i < results.size(); i++) {
                Object[] row = results.get(i);
                loads[i] = new SedimentLoad(
                    (String) row[0],
                    (Date) row[1],
                    null,
                    false,
                    "");
            }
            return loads;
        }
        else if (type.equals("epoch")) {
            sqlQuery = session.createSQLQuery(SQL_SELECT_EPOCHS)
                .addScalar("description", StandardBasicTypes.STRING)
                .addScalar("startYear", StandardBasicTypes.DATE)
                .addScalar("end", StandardBasicTypes.DATE);
            sqlQuery.setString("name", river);
            sqlQuery.setDouble("startKm", startKm);
            sqlQuery.setDouble("endKm", endKm);
            List<Object []> results = sqlQuery.list();

            SedimentLoad[] loads = new SedimentLoad[results.size()];
            for (int i = 0; i < results.size(); i++) {
                Object[] row = results.get(i);
                loads[i] = new SedimentLoad(
                    (String) row[0],
                    (Date) row[1],
                    (Date) row[2],
                    true,
                    "");
            }
            return loads;
        }
        else if (type.equals("off_epoch")) {
            sqlQuery = session.createSQLQuery(SQL_SELECT_OFFEPOCHS)
                .addScalar("startYear", StandardBasicTypes.DATE)
                .addScalar("end", StandardBasicTypes.DATE);
            sqlQuery.setString("name", river);
            sqlQuery.setDouble("startKm", startKm);
            sqlQuery.setDouble("endKm", endKm);
            List<Object []> results = sqlQuery.list();

            SedimentLoad[] loads = new SedimentLoad[results.size()];
            for (int i = 0; i < results.size(); i++) {
                Object[] row = results.get(i);
                loads[i] = new SedimentLoad(
                    ((Date) row[0]).toString() + (Date) row[1],
                    (Date) row[0],
                    (Date) row[1],
                    true,
                    "");
            }
            return loads;
        }
        else {
             log.warn("getSedimentLoadsUncached does not understand type " + type);
        }
        return new SedimentLoad[0];
    }

    /**
     * Get a specific sediment load from db.
     *
     * @param id the sediment yields id.
     *
     * @return according sediment load.
     */
    public static SedimentLoad getSedimentLoadWithDataUncached(
        String id,
        String river
    ) {
        log.debug("SedimentLoadFactory.getSedimentLoadWithDataUncached / id " + id);
        Session session = SessionHolder.HOLDER.get();
        SQLQuery sqlQuery = null;

        // Measurement stations: all, for float-stuff, for suspended stuff.
        // Because they need fast sorted access, use TreeMaps.
        // They map the starting validity range km to the station itself.
        List<MeasurementStation> allStations =
            RiverFactory.getRiver(river).getMeasurementStations();
        TreeMap<Double,MeasurementStation> floatStations =
            new TreeMap<Double, MeasurementStation>();
        TreeMap<Double,MeasurementStation> suspStations =
            new TreeMap<Double, MeasurementStation>();

        // From all stations, sort into the two kinds, skip undefined ones.
        for (MeasurementStation measurementStation: allStations) {
            if (measurementStation.getMeasurementType() == null ||
                measurementStation.getRange() == null) {
                continue;
            }
            if (measurementStation.getMeasurementType().equals("Schwebstoff")) {
                suspStations.put(
                    measurementStation.getRange().getA().doubleValue(),
                    measurementStation);
            }
            else if (measurementStation.getMeasurementType().equals("Geschiebe")) {
                floatStations.put(
                    measurementStation.getRange().getA().doubleValue(),
                    measurementStation);
            }
        }

        sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLES_DATA_BY_ID)
            .addScalar("description", StandardBasicTypes.STRING)
            .addScalar("load", StandardBasicTypes.DOUBLE)
            .addScalar("km", StandardBasicTypes.DOUBLE)
            .addScalar("fraction", StandardBasicTypes.STRING)
            .addScalar("unit", StandardBasicTypes.STRING);
        sqlQuery.setInteger("id", Integer.valueOf(id));

        List<Object []> results = sqlQuery.list();
        SedimentLoad load = new SedimentLoad();
        if (results.isEmpty()) {
            log.warn("Empty result for year calculation.");
        }
        else {
            Object[] row = results.get(0);
            load = new SedimentLoad(
                    (String) row[0], //description
                    null,//(Date) row[1], //start
                    null,  //end
                    false, //isEpoch
                    (String) row[4]); //unit

            String fraction = (String) row[3];

            TreeMap<Double,MeasurementStation> relevantStations = 
                fraction.equals("suspended_sediment") /* || TODO clarify: fraction.equals("susp_sand") */
                ? suspStations
                : floatStations;

            for (int i = 0; i < results.size(); i++) {
                row = results.get(i);
                double km = (Double) row[2];
                Range range = findMeasurementStationRange(relevantStations, km);
                if (range == null) {
                    log.warn("No measurement station for " + fraction + " km " + km);
                    continue;
                }

                double v = -1;

                if (row[1] != null) {
                    v = ((Double)row[1]).doubleValue();
                }

                setLoadFraction(load, km, v, range, fraction);
            }

        }

        return load;
    }

    /**
     * Get sediment loads from db.
     *
     * @param river the river
     * @param type the sediment load type (year, epoch or off_epoch)
     *
     * @return according sediment loads.
     */
    public static SedimentLoad getSedimentLoadWithDataUncached(
        String river,
        String type,
        double startKm,
        double endKm,
        int syear,
        int eyear
    ) {
        log.debug("SedimentLoadFactory.getSedimentLoadWithDataUncached");
        Session session = SessionHolder.HOLDER.get();
        SQLQuery sqlQuery = null;

        // Measurement stations: all, for float-stuff, for suspended stuff.
        // Because they need fast sorted access, use TreeMaps.
        // They map the starting validity range km to the station itself.
        List<MeasurementStation> allStations =
            RiverFactory.getRiver(river).getMeasurementStations();
        TreeMap<Double,MeasurementStation> floatStations =
            new TreeMap<Double, MeasurementStation>();
        TreeMap<Double,MeasurementStation> suspStations =
            new TreeMap<Double, MeasurementStation>();

        // From all stations, sort into the two kinds, skip undefined ones.
        for (MeasurementStation measurementStation: allStations) {
            if (measurementStation.getMeasurementType() == null ||
                measurementStation.getRange() == null) {
                continue;
            }
            if (measurementStation.getMeasurementType().equals("Schwebstoff")) {
                suspStations.put(
                    measurementStation.getRange().getA().doubleValue(),
                    measurementStation);
            }
            else if (measurementStation.getMeasurementType().equals("Geschiebe")) {
                floatStations.put(
                    measurementStation.getRange().getA().doubleValue(),
                    measurementStation);
            }
        }

        // Construct date constraint.
        Calendar start = Calendar.getInstance();
        start.set(syear - 1, 11, 31);
        Calendar end = Calendar.getInstance();
        end.set(syear, 11, 30);

        if (type.equals("year") || type.equals("epoch")) {
            sqlQuery = session.createSQLQuery(SQL_SELECT_SINGLES_DATA)
                .addScalar("description", StandardBasicTypes.STRING)
                .addScalar("year", StandardBasicTypes.DATE)
                .addScalar("load", StandardBasicTypes.DOUBLE)
                .addScalar("km", StandardBasicTypes.DOUBLE)
                .addScalar("unit", StandardBasicTypes.STRING);
            sqlQuery.setString("name", river);
            sqlQuery.setDouble("startKm", startKm);
            sqlQuery.setDouble("endKm", endKm);
            sqlQuery.setDate("begin", start.getTime());
            sqlQuery.setDate("end", end.getTime());
            sqlQuery.setString("grain", "total");
            List<Object []> results = sqlQuery.list();
            SedimentLoad load = new SedimentLoad();
            if (results.isEmpty()) {
                log.warn("Empty result for year calculation.");
            }
            else {
                Object[] row = results.get(0);
                load = new SedimentLoad(
                        (String) row[0], //description
                        (Date) row[1], //start
                        null,  //end
                        false, //isEpoch
                        (String) row[4]); //unit
            }
            load = getValues("coarse", sqlQuery, load, floatStations);
            load = getValues("fine_middle", sqlQuery, load, floatStations);
            load = getValues("sand", sqlQuery, load, floatStations);
            load = getValues("suspended_sediment", sqlQuery, load, suspStations);
            load = getValues("susp_sand_bed", sqlQuery, load, floatStations);
            load = getValues("susp_sand", sqlQuery, load, floatStations);

            return load;
        }
        else if (type.equals("off_epoch")) {
            // Set calendars to fetch the epochs by their start and end
            // dates.
            Calendar toStart = Calendar.getInstance();
            toStart.set(eyear - 1, 11, 31);
            Calendar toEnd = Calendar.getInstance();
            toEnd.set(eyear+1, 00, 01);
            // Set query parameters.
            sqlQuery = session.createSQLQuery(SQL_SELECT_EPOCHS_DATA)
                .addScalar("description", StandardBasicTypes.STRING)
                .addScalar("startYear", StandardBasicTypes.DATE)
                .addScalar("load", StandardBasicTypes.DOUBLE)
                .addScalar("km", StandardBasicTypes.DOUBLE)
                .addScalar("endYear", StandardBasicTypes.DATE)
                .addScalar("unit", StandardBasicTypes.STRING);
            sqlQuery.setString("name", river);
            sqlQuery.setDouble("startKm", startKm);
            sqlQuery.setDouble("endKm", endKm);
            sqlQuery.setDate("sbegin", start.getTime());
            sqlQuery.setDate("send", end.getTime());
            sqlQuery.setDate("ebegin", toStart.getTime());
            sqlQuery.setDate("eend", toEnd.getTime());
            sqlQuery.setString("grain", "total");

            List<Object[]> results = null;
            results = sqlQuery.list();

            SedimentLoad load = null;
            if (results.isEmpty()) {
                log.warn("No total results for off-epoch");
            }
            else {
                Object[] row = results.get(0);
                load = new SedimentLoad(
                        (String) row[0],
                        (Date) row[1],
                        (Date) row[4],
                        true,
                        (String)row[5]);
                TDoubleArrayList kms = new TDoubleArrayList();
                for (int i = 0; i < results.size(); i++) {
                    row = results.get(i);
                    kms.add((Double)row[3]);
                    load.setLoadTotal((Double)row[3], (Double)row[2]);
                }
            }
            load = getValues("coarse", sqlQuery, load, floatStations);
            load = getValues("fine_middle", sqlQuery, load, floatStations);
            load = getValues("sand", sqlQuery, load, floatStations);
            load = getValues("suspended_sediment", sqlQuery, load, suspStations);
            load = getValues("susp_sand_bed", sqlQuery, load, floatStations);
            load = getValues("susp_sand", sqlQuery, load, floatStations);
            return load;
        }
        return new SedimentLoad();
    }

    protected static Range findMeasurementStationRange(
        TreeMap<Double, MeasurementStation> stations,
        double km
    ) {
        MeasurementStation station = stations.get(km);
        if (station == null) {
            return null;
        }

        double endKm;

        if (stations.ceilingEntry(km + 0.1d) != null) {
            MeasurementStation nextStation = stations.ceilingEntry(km + 0.1d).getValue();
            endKm = nextStation.getRange().getA().doubleValue();
        }
        else {
            // TODO end-of-river instead of B.
            endKm = station.getRange().getB().doubleValue();
        }

        return new Range(
            station.getRange().getA().doubleValue(),
            endKm);
    }

    /**
     * Run query with grain parameter set to fraction, feed result into
     * load. Create load if null.
     *
     * @param fraction value to set 'grain' parameter in query to.
     * @param query query in which to set 'grain' parameter and run.
     * @param load[out] SedimentLoad which to populate with values. if null
     *                  and values are found, return a new load.
     * @return param load or new load if null.
     */
    protected static SedimentLoad getValues (
        String fraction,
        SQLQuery query,
        SedimentLoad load,
        TreeMap<Double, MeasurementStation> stations
    ) {
        query.setString("grain", fraction);
        List<Object[]> results = query.list();

        // We have the first results for this query, create new load.
        if (!results.isEmpty() && load == null) {
           Object[] row = results.get(0);
           load = new SedimentLoad(
                   (String) row[0],
                   (Date) row[1],
                   (Date) row[4],
                   true,
                   (String)row[5]);
        }

        for (int i = 0; i < results.size(); i++) {
            Object[] row = results.get(i);
            double km = (Double)row[3];
            Range range = findMeasurementStationRange(stations, km);
            if (range == null) {
                log.warn("No measurement station for " + fraction + " km " + km);
                continue;
            }
            double v = -1;

            if (row[2] != null) {
                v = ((Double)row[2]).doubleValue();
            }

            setLoadFraction(load, km, v, range, fraction);
        }

        if (results.isEmpty()) {
            log.warn("No " + fraction + " values found.");
        }

        return load;
    }


    /** Set a fraction value of load to given km, value and range. */
    private static void setLoadFraction(
        SedimentLoad load, double km, double v, Range range, String fraction) {
        if (fraction.equals("coarse")) {
            load.setCoarse(km, v, range);
        }
        else if (fraction.equals("sand")) {
            load.setSand(km, v, range);
        }
        else if (fraction.equals("fine_middle")) {
            load.setFineMiddle(km, v, range);
        }
        else if (fraction.equals("suspended_sediment")) {
            load.setSuspSediment(km, v, range);
        }
        else if (fraction.equals("susp_sand")) {
            load.setSuspSand(km, v, range);
        }
        else if (fraction.equals("susp_sand_bed")) {
            load.setSuspSandBed(km, v, range);
        }
        else {
            log.error("Unknown fraction type " + fraction);
        }
    }

    public static SedimentLoad getLoadUnknown(
        String river,
        String description
    ) {
        log.debug("SedimentLoadFactory.getLoadWithData");
        Cache cache = CacheFactory.getCache(LOAD_DATA_CACHE_NAME);

        if (cache == null) {
            log.debug("Cache not configured.");
            return getSedimentLoadUnknownUncached(river, description);
        }

        StaticSedimentLoadCacheKey key =
            new StaticSedimentLoadCacheKey(river, 0d, 0d, 0, 0);

        Element element = cache.get(key);

        if (element != null) {
            log.debug("SedimentLoad found in cache");
            return (SedimentLoad)element.getValue();
        }

        SedimentLoad values = getSedimentLoadUnknownUncached(river, description);

        if (values != null && key != null) {
            log.debug("Store static bed height values in cache.");
            element = new Element(key, values);
            cache.put(element);
        }
        return values;
    }

    /**
     * Get sediment loads with fraction 'unknown' from db.
     * @param river the river
     * @param type the sediment load type (year or epoch)
     * @return according sediment loads.
     */
    public static SedimentLoad getSedimentLoadUnknownUncached(
        String river,
        String description
    ) {
        log.debug("SedimentLoadFactory.getSedimentLoadWithDataUncached");
        Session session = SessionHolder.HOLDER.get();
        SQLQuery sqlQuery = null;

        sqlQuery = session.createSQLQuery(SQL_SELECT_UNKNOWN_DATA)
            .addScalar("description", StandardBasicTypes.STRING)
            .addScalar("startYear", StandardBasicTypes.DATE)
            .addScalar("end", StandardBasicTypes.DATE)
            .addScalar("load", StandardBasicTypes.DOUBLE)
            .addScalar("km", StandardBasicTypes.DOUBLE)
            .addScalar("unit", StandardBasicTypes.STRING);
        sqlQuery.setString("name", river);
        sqlQuery.setString("descr", description);
        List<Object []> results = sqlQuery.list();
        SedimentLoad load = new SedimentLoad();
        if (results.isEmpty()) {
            return new SedimentLoad();
        }
        Object[] row = results.get(0);
        load = new SedimentLoad(
            (String) row[0],
            (Date) row[1],
            (Date) row[2],
            false,
            (String)row[5]);

        for (int i = 0; i < results.size(); i++) {
            row = results.get(i);
            SedimentLoadFraction fraction = new SedimentLoadFraction();
            fraction.setUnknown((Double)row[3]);
            load.addKm((Double)row[4], fraction);
        }
        return load;
    }

    /**
     * Return sediment loads with 'unknown' fraction type.
     * @param river Name of the river
     * @param unit Restrict result set to those of given unit.
     * @param type Type like year, epoch, off_epoch
     */
    public static SedimentLoad[] getSedimentLoadUnknown(
        String river,
        String unit,
        String type) {
        Session session = SessionHolder.HOLDER.get();
        SQLQuery sqlQuery = session.createSQLQuery(SQL_SELECT_UNKNOWN)
            .addScalar("description", StandardBasicTypes.STRING)
            .addScalar("startYear", StandardBasicTypes.DATE)
            .addScalar("end", StandardBasicTypes.DATE);
        sqlQuery.setString("river", river);
        sqlQuery.setString("unit", unit);
        if (type.equals("off_epoch")) {
            sqlQuery.setInteger("type", 1);
        }
        else {
            sqlQuery.setInteger("type", 0);
        }
        List<Object[]> results = sqlQuery.list();
        SedimentLoad[] loads = new SedimentLoad[results.size()];
        int counter = 0;
        for (Object[] row: results) {
            loads[counter] = new SedimentLoad(
                (String)row[0], (Date)row[1], (Date)row[2], false, "");
            counter++;
        }
        return loads;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org