view artifacts/src/main/java/org/dive4elements/river/artifacts/states/DefaultState.java @ 9425:3f49835a00c3

Extended CrossSectionFacet so it may fetch different data from within the artifact result. Also allows to have acces to the potentially already computed artifact result via its normal computation cache.
author gernotbelger
date Fri, 17 Aug 2018 15:31:02 +0200
parents 2323d005f9a5
children
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;

import java.text.NumberFormat;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.log4j.Logger;
import org.dive4elements.artifactdatabase.ProtocolUtils;
import org.dive4elements.artifactdatabase.data.StateData;
import org.dive4elements.artifactdatabase.state.AbstractState;
import org.dive4elements.artifactdatabase.state.Facet;
import org.dive4elements.artifacts.Artifact;
import org.dive4elements.artifacts.ArtifactNamespaceContext;
import org.dive4elements.artifacts.CallContext;
import org.dive4elements.artifacts.CallMeta;
import org.dive4elements.artifacts.common.utils.XMLUtils;
import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator;
import org.dive4elements.river.artifacts.D4EArtifact;
import org.dive4elements.river.artifacts.resources.Resources;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class DefaultState extends AbstractState {

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

    /** The three possible compute types. */
    public static enum ComputeType {
        FEED, ADVANCE, INIT
    }

    protected StateData getData(final D4EArtifact artifact, final String name) {
        return artifact.getData(name);
    }

    /**
     * Append to a node and return xml description relevant for gui.
     */
    public Element describeStatic(final Artifact artifact, final Document document, final Node root, final CallContext context, final String uuid) {
        final ElementCreator creator = new ElementCreator(document, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX);

        final CallMeta meta = context.getMeta();

        String helpText = getHelpText();
        if (helpText != null) {
            helpText = replaceHelpUrl(Resources.getMsg(meta, helpText, helpText));
        }

        final String label = Resources.getMsg(meta, getID(), getID());
        final Element ui = ProtocolUtils.createArtNode(creator, "state", new String[] { "name", "uiprovider", "label", "helpText" },
                new String[] { getID(), getUIProvider(), label, helpText });

        final Map<String, StateData> theData = getData();
        if (theData == null) {
            return ui;
        }

        final D4EArtifact flys = (D4EArtifact) artifact;

        for (final String name : theData.keySet()) {
            appendStaticData(flys, context, creator, ui, name);
        }

        return ui;
    }

    protected void appendStaticData(final D4EArtifact flys, final CallContext context, final ElementCreator cr, final Element ui, final String name) {
        final StateData data = getData(flys, name);
        final String value = (data != null) ? (String) data.getValue() : null;

        if (value == null) {
            return;
        }

        final String type = data.getType();

        if (log.isDebugEnabled()) {
            log.debug("Append element " + type + "'" + name + "' (" + value + ")");
        }

        final Element e = createStaticData(flys, cr, context, name, value, type);

        ui.appendChild(e);

    }

    /**
     * Creates a <i>data</i> element used in the static part of the DESCRIBE
     * document.
     *
     * @param creator
     *            The ElementCreator that is used to build new Elements.
     * @param cc
     *            The CallContext object used for nested i18n retrieval.
     * @param name
     *            The name of the data item.
     * @param value
     *            The value as string.
     *
     * @return an Element.
     */
    protected Element createStaticData(final D4EArtifact flys, final ElementCreator creator, final CallContext cc, final String name, final String value,
            final String type) {
        final Element dataElement = creator.create("data");
        creator.addAttr(dataElement, "name", name, true);
        creator.addAttr(dataElement, "type", type, true);

        final Element itemElement = creator.create("item");
        creator.addAttr(itemElement, "value", value, true);

        creator.addAttr(itemElement, "label", getLabelFor(cc, name, value, type), true);

        dataElement.appendChild(itemElement);

        return dataElement;
    }

    /**
     * @param cc
     * @param name
     * @param value
     * @param type
     *
     * @return
     */
    protected String getLabelFor(final CallContext cc, final String name, final String value, final String type) {
        final CallMeta meta = cc.getMeta();

        try {
            // XXX A better way to format the output would be to use the
            // 'type' value of the data objects.
            final double doubleVal = Double.parseDouble(value);
            final Locale l = Resources.getLocale(meta);
            final NumberFormat nf = NumberFormat.getInstance(l);

            return nf.format(doubleVal);
        }
        catch (final NumberFormatException nfe) {
            return Resources.getMsg(meta, value, value);
        }
    }

    /**
     * This method returns the default value and label for <i>data</i>.
     *
     * Override this method in a subclass to set an appropiate default
     * value.
     * The default label can be ignored by the client (e.g. the gwt-client).
     * but shall not be null.
     *
     * Example implementation:
     * if (data != null && data.getName().equals("the_answer")) {
     * return new String[] {"42", "the_answer"};
     * }
     *
     * @param context
     *            The CallContext used for i18n.
     * @param data
     *            The data objects that the defaults are for.
     * @return a String[] with [default value, default label].
     */
    protected String[] getDefaultsFor(final CallContext context, final StateData data) {
        return null;
    }

    @Override
    public Element describe(final Artifact artifact, final Document document, final Node root, final CallContext context, final String uuid) {
        final ElementCreator creator = new ElementCreator(document, ArtifactNamespaceContext.NAMESPACE_URI, ArtifactNamespaceContext.NAMESPACE_PREFIX);

        String helpText = getHelpText();
        if (helpText != null) {
            helpText = replaceHelpUrl(Resources.getMsg(context.getMeta(), helpText, helpText));
        }

        Element ui = null;
        final String uiprovider = getUIProvider();
        if (uiprovider != null) {
            ui = ProtocolUtils.createArtNode(creator, "dynamic", new String[] { "uiprovider", "helpText" }, new String[] { uiprovider, helpText });
        } else {
            ui = ProtocolUtils.createArtNode(creator, "dynamic", new String[] { "helpText" }, new String[] { helpText });
        }

        final Map<String, StateData> theData = getData();
        if (theData == null) {
            return ui;
        }

        final D4EArtifact flys = (D4EArtifact) artifact;

        for (final String name : theData.keySet()) {
            StateData data = getData(flys, name);

            if (data == null) {
                data = getData(name);
            }

            final Element select = createData(creator, artifact, data, context);

            final String[] defaults = getDefaultsFor(context, data);
            if (defaults != null && defaults.length > 1) {
                creator.addAttr(select, "defaultValue", defaults[0], true);
                creator.addAttr(select, "defaultLabel", defaults[1], true);
            }

            appendItems(artifact, creator, name, context, select);
            ui.appendChild(select);
        }

        return ui;
    }

    /**
     * @param artifact
     * @param creator
     * @param name
     * @param context
     * @param select
     */
    protected void appendItems(final Artifact artifact, final ElementCreator creator, final String name, final CallContext context, final Element select) {
        final Element choices = ProtocolUtils.createArtNode(creator, "choices", null, null);

        select.appendChild(choices);

        final Element[] items = createItems(creator, artifact, name, context);
        if (items != null) {
            for (final Element item : items) {
                choices.appendChild(item);
            }
        }
    }

    /**
     * This method creates the root node that contains the list of selectable
     * items.
     *
     * @param cr
     *            The ElementCreator.
     *
     * @return the root node of the item list.
     */
    protected Element createData(final ElementCreator cr, final Artifact artifact, final StateData data, final CallContext context) {
        final Element select = ProtocolUtils.createArtNode(cr, "select", null, null);
        cr.addAttr(select, "name", data.getName(), true);

        final Element label = ProtocolUtils.createArtNode(cr, "label", null, null);

        select.appendChild(label);

        label.setTextContent(Resources.getMsg(context.getMeta(), getID(), getID()));

        return select;
    }

    /**
     * This method creates a list of items. These items represent the amount of
     * input data that is possible for this state.
     *
     * @param cr
     *            The ElementCreator.
     * @param name
     *            The name of the amount of data.
     *
     * @return a list of items.
     */
    protected Element[] createItems(final ElementCreator cr, final Artifact artifact, final String name, final CallContext context) {
        return null;
    }

    /**
     * This method is used to create an <i>item</i> Element that contains two
     * further elements <i>label</i> and <i>value</i>. The label and value
     * elements both have text nodes.
     *
     * @param cr
     *            The ElementCreator used to build new Elements.
     * @param obj
     *            This implementation awaits a String array with [0] = label and
     *            [1] = value.
     *
     * @return an Element.
     */
    protected static Element createItem(final XMLUtils.ElementCreator cr, final Object obj) {
        final Element item = ProtocolUtils.createArtNode(cr, "item", null, null);
        final Element label = ProtocolUtils.createArtNode(cr, "label", null, null);
        final Element value = ProtocolUtils.createArtNode(cr, "value", null, null);

        final String[] arr = (String[]) obj;

        label.setTextContent(arr[0]);
        value.setTextContent(arr[1]);

        item.appendChild(label);
        item.appendChild(value);

        return item;
    }

    // protected static Element createItem(final XMLUtils.ElementCreator cr, final Object obj) {
    // final Element item = ProtocolUtils.createArtNode(cr, "item", null, null);
    // final Element label = ProtocolUtils.createArtNode(cr, "label", null, null);
    // final Element value = ProtocolUtils.createArtNode(cr, "value", null, null);
    //
    // final String[] arr = (String[]) obj;
    //
    // label.setTextContent(arr[0]);
    // value.setTextContent(arr[1]);
    //
    // item.appendChild(label);
    // item.appendChild(value);
    //
    // return item;
    // }

    /**
     * This method transform a given value into a StateData object.
     *
     * @param flys
     *            The D4EArtifact.
     * @param name
     *            The name of the data object.
     * @param val
     *            The value of the data object.
     *
     * @return a StateData object with <i>name</i> and <i>val</i>ue.
     */
    public StateData transform(final D4EArtifact flys, final CallContext cc, final StateData stateData, final String name, final String val) {
        if (log.isDebugEnabled()) {
            log.debug("Transform data ('" + name + "','" + val + "')");
        }

        stateData.setValue(val);

        return stateData;
    }

    /**
     * Override this to do validation.
     *
     * Throw an IllegalArgumentException with a localized
     * error message that should be presented to the user in case
     * the date provided is invalid.
     */
    public void validate(final Artifact artifact, final CallContext context) throws IllegalArgumentException {
        validate(artifact); /*
                             * For compatibility so that classes that
                             * override this method still work.
                             */
    }

    /**
     * This method is deprecated.
     * Override the function with the callcontext instead to do
     * localization of error.s
     */
    public boolean validate(final Artifact artifact) throws IllegalArgumentException {
        return true;
    }

    /**
     * Returns which UIProvider shall be used to aid user input.
     */
    protected String getUIProvider() {
        return null;
    }

    public Object computeAdvance(final D4EArtifact artifact, final String hash, final CallContext context, final List<Facet> facets, final Object old) {
        return null;
    }

    public Object computeFeed(final D4EArtifact artifact, final String hash, final CallContext context, final List<Facet> facets, final Object old) {
        return null;
    }

    public Object computeInit(final D4EArtifact artifact, final String hash, final Object context, final CallMeta meta, final List<Facet> facets) {
        return null;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :

http://dive4elements.wald.intevation.org