view artifacts/src/main/java/org/dive4elements/river/artifacts/states/minfo/BedQualityPeriodsSelect.java @ 8682:5102733c4567

issue1755 Prevent out of bounds access when there is no data If there is no data it will default to the complete river. In the following overview you can then see that there is no data. Better then a "Error changing state".
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 13 Apr 2015 11:03:00 +0200
parents 22f01b7e802e
children 8dbb969091c5
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.states.minfo;

import java.util.List;
import java.util.Date;
import java.util.TreeSet;
import java.text.DateFormat;

import org.apache.log4j.Logger;

import org.dive4elements.river.artifacts.states.DefaultState;

import org.w3c.dom.Element;

import org.dive4elements.river.artifacts.access.RangeAccess;
import org.dive4elements.river.artifacts.access.BedQualityAccess;
import org.dive4elements.river.artifacts.D4EArtifact;
import org.dive4elements.river.artifacts.model.minfo.BedOverview;
import org.dive4elements.river.artifacts.model.minfo.BedOverviewFactory;
import org.dive4elements.river.artifacts.model.minfo.BedloadOverview;
import org.dive4elements.river.artifacts.model.minfo.BedloadOverviewFactory;
import org.dive4elements.river.artifacts.model.DateRange;
import org.dive4elements.river.artifacts.resources.Resources;

import org.dive4elements.river.utils.Formatter;
import org.dive4elements.river.utils.KMIndex;

import org.dive4elements.artifacts.common.utils.XMLUtils;
import org.dive4elements.artifacts.Artifact;
import org.dive4elements.artifacts.CallContext;

import org.dive4elements.artifactdatabase.data.StateData;


public class BedQualityPeriodsSelect extends DefaultState {

    /** The log used in this class. */
    private static Logger log = Logger.getLogger(BedQualityPeriodsSelect.class);

    private static final String I18N_NO_DATA =
        "state.minfo.bed.error.no_data";

    private static final String I18N_NO_DATA_FOR_PERIOD =
        "state.minfo.bed.error.no_data_for_period";

    /**
     * The default constructor that initializes an empty State object.
     */
    public BedQualityPeriodsSelect() {
    }

    /** Get either the start and end date of the data at the current position. */
    protected Long[] getDataMinMaxDate(Artifact artifact) {
        D4EArtifact arti = (D4EArtifact) artifact;
        RangeAccess access = new RangeAccess(arti);
        double a = access.getFrom(true);
        double b = access.getTo(true);

        BedOverview overview = BedOverviewFactory.getOverview(access.getRiverName());
        BedloadOverview overview2 = BedloadOverviewFactory.getOverview(access.getRiverName());

        /* Filter is not implemented and only checks if a complete
         * KMIndex list is acceptable or not. So KMFiltering wont work */
        KMIndex<List<Date>> entries = overview.filter(BedOverview.ACCEPT);
        KMIndex<List<Date>> loads = overview2.filter(BedloadOverview.ACCEPT);
        TreeSet<Date> allDates = new TreeSet<Date>();

        for (int i = 0; i < entries.size(); i++) {
            if (entries.get(i).getKm() >= a && entries.get(i).getKm() <= b) {
                allDates.addAll(entries.get(i).getValue());
            }
        }
        for (int i = 0; i < loads.size(); i++) {
            if (loads.get(i).getKm() >= a && loads.get(i).getKm() <= b) {
                allDates.addAll(loads.get(i).getValue());
            }
        }
        if (allDates.size() < 2) {
            return null;
        }

        return new Long[] {allDates.first().getTime(),
                           allDates.last().getTime()};
    }

    @Override
    protected Element[] createItems(
        XMLUtils.ElementCreator cr,
        Artifact    artifact,
        String      name,
        CallContext context)
    {
        if (!name.equals("periods")) {
            return null;
        }
        Long[] values = getDataMinMaxDate(artifact);
        if (values == null) {
            return null;
        }
        Element def = createItem(
            cr,
            new String[] {"default", values[0].toString() + "," + values[1].toString()});

        return new Element[] { def };
    }

    @Override
    public void validate(Artifact artifact, CallContext context)
    throws IllegalArgumentException {
        D4EArtifact arti = (D4EArtifact) artifact;
        BedQualityAccess access = new BedQualityAccess(arti, context);

        Long[] minMax = getDataMinMaxDate(artifact);
        if (minMax == null) {
            throw new IllegalArgumentException(Resources.getMsg(context.getMeta(),
                         I18N_NO_DATA,
                         I18N_NO_DATA));
        }

        long min = minMax[0];
        long max = minMax[1];
        for (DateRange range: access.getDateRanges()) {
            long a = range.getFrom().getTime();
            long b = range.getTo().getTime();
            log.debug("min max a b " + min + " " + max + " " + a + " " + b);
            if (b < min || a > max || a > b) {
                DateFormat df = Formatter.getDateFormatter(context.getMeta(), "dd.MM.yyyy");
                throw new IllegalArgumentException(Resources.getMsg(context.getMeta(),
                             I18N_NO_DATA_FOR_PERIOD,
                             I18N_NO_DATA_FOR_PERIOD,
                             new Object[] {df.format(range.getFrom()),
                                           df.format(range.getTo())}));
            }
        }
    }

    @Override
    protected String getUIProvider() {
        return "bedquality_periods_select";
    }

}

http://dive4elements.wald.intevation.org