view flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java @ 121:e0ded17a4846

Implemented the feed() operation. flys-artifacts/trunk@1442 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Wed, 09 Mar 2011 14:13:57 +0000
parents 84c0b151203e
children d3b8b0b1d010
line wrap: on
line source
package de.intevation.flys.artifacts;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.xpath.XPathConstants;

import org.apache.log4j.Logger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import de.intevation.artifacts.ArtifactFactory;
import de.intevation.artifacts.CallContext;

import de.intevation.artifacts.common.ArtifactNamespaceContext;
import de.intevation.artifacts.common.utils.XMLUtils;

import de.intevation.artifactdatabase.DefaultArtifact;
import de.intevation.artifactdatabase.data.DefaultStateData;
import de.intevation.artifactdatabase.data.StateData;
import de.intevation.artifactdatabase.state.State;
import de.intevation.artifactdatabase.state.StateEngine;

import de.intevation.flys.artifacts.context.FLYSContext;


/**
 * The defaul FLYS artifact.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public abstract class FLYSArtifact extends DefaultArtifact {

    /** The logger that is used in this artifact.*/
    private static Logger logger = Logger.getLogger(FLYSArtifact.class);


    /** The XPath that points to the input data elements of the FEED document.*/
    public static final String XPATH_FEED_INPUT =
        "/art:action/art:data/art:input";


    /** The identifier of the current state. */
    protected String currentStateId;

    /** The name of the artifact.*/
    protected String name;

    /** The data that have been inserted into this artifact.*/
    protected Map<String, StateData> data;


    /**
     * The default constructor that creates an empty FLYSArtifact.
     */
    public FLYSArtifact() {
        data = new HashMap<String, StateData>();
    }


    /**
     * Returns the name of the concrete artifact.
     *
     * @return the name of the concrete artifact.
     */
    public abstract String getName();


    /**
     * Returns the FLYSContext from context object.
     *
     * @param context The CallContext or the FLYSContext.
     *
     * @return the FLYSContext.
     */
    protected FLYSContext getFlysContext(Object context) {
        return context instanceof FLYSContext
            ? (FLYSContext) context
            : (FLYSContext) ((CallContext) context).globalContext();
    }


    /**
     * Initialize the artifact and insert new data if <code>data</code> contains
     * information necessary for this artifact.
     *
     * @param identifier The UUID.
     * @param factory The factory that is used to create this artifact.
     * @param context The CallContext.
     * @param data Some optional data.
     */
    @Override
    public void setup(
        String          identifier,
        ArtifactFactory factory,
        Object          context,
        Document        data)
    {
        logger.debug("Setup this artifact with the uuid: " + identifier);

        super.setup(identifier, factory, context, data);

        FLYSContext flysContext = (FLYSContext) context;
        StateEngine engine      = (StateEngine) flysContext.get(
            FLYSContext.STATE_ENGINE_KEY);

        String name = getName();

        logger.debug("Set initial state for artifact '" + name + "'");
        List<State> states = engine.getStates(name);

        setCurrentState(states.get(0));
    }


    /**
     * Insert new data included in <code>input</code> into the current state.
     *
     * @param target XML document that contains new data.
     * @param context The CallContext.
     *
     * @return a document that contains a SUCCESS or FAILURE message.
     */
    @Override
    public Document feed(Document target, CallContext context) {
        Document doc = XMLUtils.newDocument();

        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
            doc,
            ArtifactNamespaceContext.NAMESPACE_URI,
            ArtifactNamespaceContext.NAMESPACE_PREFIX);

        Element result = creator.create("result");
        doc.appendChild(result);

        try {
            saveData(target, XPATH_FEED_INPUT);
            creator.addAttr(result, "type", "SUCCESS", true);
        }
        catch (IllegalArgumentException iae) {
            creator.addAttr(result, "type", "FAILURE", true);

            // TODO I18N this message - getMessage() returns a lookup string, no
            // human readable error message
            result.setTextContent(iae.getMessage());
        }

        return doc;
    }


    /**
     * Returns the identifier of the current state.
     *
     * @return the identifier of the current state.
     */
    protected String getCurrentStateId() {
        return currentStateId;
    }


    /**
     * Sets the identifier of the current state.
     *
     * @param id the identifier of a state.
     */
    protected void setCurrentStateId(String id) {
        currentStateId = id;
    }


    /**
     * Set the current state of this artifact. <b>NOTE</b>We don't store the
     * State object itself - which is not necessary - but its identifier. So
     * this method will just call the setCurrentStateId() method with the
     * identifier of <i>state</i>.
     *
     * @param state The new current state.
     */
    protected void setCurrentState(State state) {
        setCurrentStateId(state.getID());
    }


    /**
     * Returns the current state of the artifact.
     *
     * @return the current State of the artifact.
     */
    protected State getCurrentState(Object context) {
        FLYSContext flysContext = getFlysContext(context);
        StateEngine engine      = (StateEngine) flysContext.get(
            FLYSContext.STATE_ENGINE_KEY);

        return engine.getState(getCurrentStateId());
    }


    /**
     * Adds a new StateData item to the data pool of this artifact.
     *
     * @param name the name of the data object.
     * @param data the data object itself.
     */
    protected void addData(String name, StateData data) {
        this.data.put(name, data);
    }


    /**
     * This method stores the data that is contained in the FEED document.
     *
     * @param feed The FEED document.
     * @param xpath The XPath that points to the data nodes.
     */
    public void saveData(Document feed, String xpath)
    throws IllegalArgumentException
    {
        if (feed == null || xpath == null || xpath.length() == 0) {
            throw new IllegalArgumentException("feed.no.input.data");
        }

        NodeList nodes = (NodeList) XMLUtils.xpath(
            feed,
            xpath,
            XPathConstants.NODESET,
            ArtifactNamespaceContext.INSTANCE);

        if (nodes == null || nodes.getLength() == 0) {
            throw new IllegalArgumentException("feed.no.input.data");
        }

        int count = nodes.getLength();
        logger.debug("Try to save " + count + " data items.");

        for (int i = 0; i < count; i++) {
            Node node = nodes.item(i);

            String name = XMLUtils.xpathString(
                node, "@art:name", ArtifactNamespaceContext.INSTANCE);
            String value = XMLUtils.xpathString(
                node, "@art:value", ArtifactNamespaceContext.INSTANCE);

            if (name != null && value != null) {
                logger.debug("Save data item for '" + name + "' : " + value);

                // TODO ADD INPUT VALIDATION!
                addData(name, new DefaultStateData(name, null, null, value));
            }
        }
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org