view flys-artifacts/src/main/java/de/intevation/flys/artifacts/WQKmsInterpolArtifact.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.List;

import org.apache.log4j.Logger;

import org.w3c.dom.Document;

import de.intevation.artifactdatabase.state.Facet;
import de.intevation.artifactdatabase.state.FacetActivity;
import de.intevation.artifactdatabase.state.DefaultOutput;
import de.intevation.artifactdatabase.state.State;

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.model.WQFacet;
import de.intevation.flys.artifacts.model.WKmsFactory;
import de.intevation.flys.artifacts.model.WQKmsFactory;
import de.intevation.flys.artifacts.model.WstValueTable;
import de.intevation.flys.artifacts.model.WstValueTableFactory;

import de.intevation.flys.artifacts.states.StaticState;
import de.intevation.flys.artifacts.resources.Resources;


/**
 * Artifact to access additional "waterlevel/discharge"-type of data, like
 * fixation measurements, but doing so with costy interpolation.
 *
 * This artifact neglects (Static)FLYSArtifacts capabilities of interaction
 * with the StateEngine by overriding the getState*-methods.
 */
public class WQKmsInterpolArtifact
extends      StaticFLYSArtifact
implements   FacetTypes
{
    /** The logger for this class. */
    private static Logger logger =
        Logger.getLogger(WQKmsInterpolArtifact.class);

    /** State name. */
    public static final String STATIC_STATE_NAME =
        "state.additional_wqkms.interpol.static";

    /** Artifact name. */
    private static final String NAME = "staticwqkmsinterpol";

    static {
        // TODO: Move to configuration.
        FacetActivity.Registry.getInstance()
            .register(NAME, FacetActivity.INACTIVE);
    }

    /** One and only state to be in. */
    protected transient State state = null;


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


    /** Return fixed artifact (types) name. */
    @Override
    public String getName() {
        return NAME;
    }


    /**
     * Gets called from factory, to set things up.
     */
    @Override
    public void setup(
        String          identifier,
        ArtifactFactory factory,
        Object          context,
        CallMeta        callMeta,
        Document        data)
    {
        logger.debug("WQKmsInterpolArtifact.setup");

        state = new StaticState(STATIC_STATE_NAME);

        List<Facet> fs = new ArrayList<Facet>();
        String code = getDatacageIDValue(data);

        // TODO Go for JSON, one day.
        //ex.: flood_protection-wstv-114-12
        if (code != null) {
            String [] parts = code.split("-");

            logger.debug("WQKmsInterpolArtifact.setup: code " + code);

            if (parts.length >= 4) {
                int wst = Integer.parseInt(parts[3]);
                int col = -1;
                String colpos = parts[2];
                // Are we interested in a single column or in all columns?
                if (colpos.equals("A")) {
                    ; // Take all.
                }
                else {
                    col = Integer.parseInt(colpos);
                    addStringData("col_pos", parts[2]);
                }
                addStringData("wst_id",  parts[3]);
                String wkmsName = (col >= 0)
                                ? WKmsFactory.getWKmsName(col, wst)
                                : WKmsFactory.getWKmsName(wst);
                String name;
                if (parts[0].startsWith("height")){
                    name = STATIC_WQ_ANNOTATIONS;
                }
                else if (parts[0].startsWith("flood")) {
                    name = STATIC_WKMS_INTERPOL;
                }
                else {
                    name = STATIC_WQ;
                }

                Facet wQFacet = new WQFacet(name,
                    Resources.getMsg(
                        callMeta,
                        wkmsName,
                        wkmsName));
                fs.add(wQFacet);
                addFacets(state.getID(), fs);
            }
        }
        else {
            logger.warn("WQKmsInterpolArtifact: no code");
        }

        spawnState();
        super.setup(identifier, factory, context, callMeta, data);
    }


    /**
     * Initialize the static state with output.
     * @return static state
     */
    protected State spawnState() {
        state = new StaticState(STATIC_STATE_NAME);
        List<Facet> fs = getFacets(STATIC_STATE_NAME);
        DefaultOutput output = new DefaultOutput(
            "general",
            "general",
            "image/png",
            fs,
            "chart");

        state.getOutputs().add(output);

        return state;
    }


    /**
     * Called via setup.
     *
     * @param artifact The master-artifact.
     */
    @Override
    protected void initialize(
        Artifact artifact,
        Object context,
        CallMeta meta)
    {
        logger.debug("WQKmsInterpolArtifact.initialize");
        FLYSArtifact winfo = (FLYSArtifact) artifact;
        importData(winfo, "river");
        importData(winfo, "ld_locations");
    }


    /**
     * Get a list containing the one and only State.
     * @param  context ignored.
     * @return list with one and only state.
     */
    @Override
    protected List<State> getStates(Object context) {
        ArrayList<State> states = new ArrayList<State>();
        states.add(getState());
        return states;
    }


    /**
     * Get WQ at a given km.
     * @param currentKm the requested km. If NULL, ld_location data
     *        will be used.
     */
    public double [][] getWQAtKm(Double currentKm) {

        WstValueTable interpolator = null;
        // Get WstValueTable
        if (getDataAsString("col_pos") != null) {
            interpolator = WstValueTableFactory.getWstColumnTable(
                getDataAsInt("wst_id"), getDataAsInt("col_pos"));
        }
        else {
            interpolator = WstValueTableFactory.getTable(
                getDataAsInt("wst_id"));
        }

        Double tmp = (currentKm != null)
                     ? currentKm
                     : getDataAsDouble("ld_locations");

        double [][] vs = interpolator.interpolateWQColumnwise(
            tmp != null ? tmp : 0);

        for (int x = 0; x < vs[1].length; x++) {
            logger.debug("getWQAtKm: Q/W " + vs[0][x] + " / " + vs[1][x]);
        }

        return vs;
    }


    /**
     * Get a DataItem casted to int (0 if fails).
     */
    public int getDataAsInt(String dataName) {
        String val = getDataAsString(dataName);
        try {
            return Integer.parseInt(val);
        }
        catch (NumberFormatException e) {
            logger.warn("Could not get data " + dataName + " as int", e);
            return 0;
        }
    }


    /**
     * Get the "current" state (there is but one).
     * @param cc ignored.
     * @return the "current" (only possible) state.
     */
    @Override
    public State getCurrentState(Object cc) {
        return getState();
    }


    /**
     * Get the only possible state.
     * @return the state.
     */
    protected State getState() {
        return getState(null, null);
    }


    /**
     * Get the state.
     * @param context ignored.
     * @param stateID ignored.
     * @return the state.
     */
    @Override
    protected State getState(Object context, String stateID) {
        return (state != null)
            ? state
            : spawnState();
    }


    /**
     * Get WQKms from factory.
     * @param idx param is not needed (TODO)
     * @return WQKms according to parameterization (can be null);
     */
    public WQKms getWQKms(int idx) {
        logger.debug("WQKmsInterpolArtifact.getWQKms");
        logger.warn("Stub, getWQKms not yet implemented.");

        return WQKmsFactory.getWQKms(
            Integer.parseInt(getDataAsString("col_pos")),
            Integer.parseInt(getDataAsString("wst_id")));
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org