view flys-artifacts/src/main/java/de/intevation/flys/artifacts/GaugeDischargeArtifact.java @ 5779:ebec12def170

Datacage: Add a pool of builders to make it multi threadable. XML DOM is not thread safe. Therefore the old implementation only allowed one thread to use the builder at a time. As the complexity of the configuration has increased over time this has become a bottleneck of the whole application because it took quiet some time to build a result. Furthermore the builder code path is visited very frequent. So many concurrent requests were piled up resulting in long waits for the users. To mitigate this problem a round robin pool of builders is used now. Each of the pooled builders has an independent copy of the XML template and can be run in parallel. The number of builders is determined by the system property 'flys.datacage.pool.size'. It defaults to 4.
author Sascha L. Teichmann <teichmann@intevation.de>
date Sun, 21 Apr 2013 12:48:09 +0200
parents a2735a4bf75e
children
line wrap: on
line source
package de.intevation.flys.artifacts;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import org.w3c.dom.Document;

import de.intevation.artifactdatabase.state.Facet;

import de.intevation.artifacts.Artifact;
import de.intevation.artifacts.ArtifactFactory;
import de.intevation.artifacts.CallMeta;

import de.intevation.flys.artifacts.model.FacetTypes;
import de.intevation.flys.artifacts.model.WQKms;

import de.intevation.flys.artifacts.states.DefaultState;

import de.intevation.flys.artifacts.model.Calculation;
import de.intevation.flys.artifacts.model.CalculationResult;

import de.intevation.flys.artifacts.model.DischargeTables;

import de.intevation.flys.model.Gauge;
import de.intevation.flys.model.River;

import de.intevation.flys.utils.FLYSUtils;


/**
 * Artifact to get discharge curves at gauges.
 */
public class GaugeDischargeArtifact
extends      WINFOArtifact
implements   FacetTypes
{
    /** The logger for this class. */
    private static Logger logger = Logger.getLogger(GaugeDischargeArtifact.class);

    /** The name of the artifact. */
    public static final String ARTIFACT_NAME = "gaugedischarge";


    /**
     * Trivial Constructor.
     */
    public GaugeDischargeArtifact() {
        logger.debug("GaugeDischargeArtifact.GaugeDischargeArtifact()");
    }


    /**
     * Gets called from factory, to set things up.
     * Especially, when loaded via datacage mechanisms, provide the
     * data document.
     * @param data filled with stuff from dc, if any.
     */
    @Override
    public void setup(
        String          identifier,
        ArtifactFactory factory,
        Object          context,
        CallMeta        callMeta,
        Document        data)
    {
        logger.debug("GaugeDischargeArtifact.setup");
        String ids = StaticFLYSArtifact.getDatacageIDValue(data);
        addStringData("ids", ids);
        logger.debug("id for gaugedischarge: " + ids);
        super.setup(identifier, factory, context, callMeta, data);
    }


    /** Return the name of this artifact. */
    public String getName() {
        return ARTIFACT_NAME;
    }


    /**
     * Setup state and facet, copy from master artifact.
     */
    @Override
    protected void initialize(Artifact art, Object context, CallMeta meta) {
        logger.debug("GaugeDischargeArtifact.initialize");
        List<Facet> fs = new ArrayList<Facet>();
        FLYSArtifact artifact = (FLYSArtifact) art;
        importData(artifact, "river");

        // Get the location(s)
        //importData(artifact, "ld_mode", ld_from, ld_to, ld_locations
        addStringData("ld_from", "0");
        addStringData("ld_to", "1000");
        addStringData("ld_mode", "distance");

        DefaultState state = (DefaultState) getCurrentState(context);
        state.computeInit(this, hash(), context, meta, fs);
        if (!fs.isEmpty()) {
            logger.debug("Facets to add in GaugeDischargeArtifact.initialize. ("
                + state.getID() + "/ " + getCurrentStateId() + ").");
            addFacets(getCurrentStateId(), fs);
        }
        else {
            logger.debug("No facets to add in GaugeDischargeArtifact.initialize ("
                + state.getID() + "/ "+getCurrentStateId()+").");
        }
    }


    /** Get the Gauges name which came with datacage data-document. */
    public String getGaugeName() {
        return this.getDataAsString("ids");
    }


    /** Get the Gauges which came with datacage data-document. */
    public Gauge getGauge() {
        River river = FLYSUtils.getRiver(this);
        return river.determineGaugeByName(getGaugeName());
    }


    /**
     * Returns the data that is used to create discharge curves.
     * @return CalculationResult with WQKms.
     */
    public CalculationResult getDischargeCurveData() {

        River river = FLYSUtils.getRiver(this);
        if (river == null) {
            return error(new WQKms[0], "no.river.selected");
        }
        /*
        // This one would allow to automatically pick the right Gauge.
        double [] distance = FLYSUtils.getKmRange(this);
        logger.debug("getDischargeCurveData: get range");

        if (distance == null) {
            return error(new WQKms[0], "no.range.found");
        }

        List<Gauge> gauges = river.determineGauges(distance[0], distance[1]);
        logger.debug("getDischargeCurveData: got " + gauges.size() + " gauges");

        if (gauges.isEmpty()) {
            return error(new WQKms[0], "no.gauge.selected");
        }

        String [] names = new String[gauges.size()];

        for (int i = 0; i < names.length; ++i) {
            names[i] = gauges.get(i).getName();
            logger.debug("getDischargeCurveData: name " + names[i]);
        }
        */

        DischargeTables dt = new DischargeTables(river.getName(), getDataAsString("ids"));

        Map<String, double [][]> map = dt.getValues(100);

        ArrayList<WQKms> res = new ArrayList<WQKms>();

        Gauge gauge = river.determineGaugeByName(this.getDataAsString("ids"));

        String name = getGaugeName();
        double [][] values = map.get(name);
        if (values == null) {
            logger.error("No values for this gauge / discharge found.");
            return error(new WQKms[0], "no.gauge.found");
        }
        for (int i = 0 ; i < values[0].length; i++) {
            values[0][i] += gauge.getDatum().doubleValue();
        }
        double [] kms = new double[values[0].length];
        Arrays.fill(kms, gauge.getStation().doubleValue());
        res.add(new WQKms(kms, values[0], values[1], name));

        return new CalculationResult(
            res.toArray(new WQKms[res.size()]),
            new Calculation());
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org