view gnv-artifacts/src/main/java/de/intevation/gnv/artifacts/fis/SelectProductArtifact.java @ 1117:dec4257ad570

Changed imports to fit new positions of XMLUtils and Config gnv-artifacts/trunk@1478 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 15 Mar 2011 16:13:39 +0000
parents f953c9a559d8
children c01c220312d0
line wrap: on
line source
/*
 * Copyright (c) 2010 by Intevation GmbH
 *
 * This program is free software under the LGPL (>=v2.1)
 * Read the file LGPL.txt coming with the software for details
 * or visit http://www.gnu.org/licenses/ if it does not exist.
 */

package de.intevation.gnv.artifacts.fis;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
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.artifactdatabase.ProxyArtifact;
import de.intevation.artifacts.common.utils.XMLUtils;
import de.intevation.artifacts.Artifact;
import de.intevation.artifacts.ArtifactFactory;
import de.intevation.artifacts.ArtifactNamespaceContext;
import de.intevation.artifacts.CallContext;
import de.intevation.artifacts.CallMeta;
import de.intevation.gnv.artifacts.GNVArtifactBase;
import de.intevation.gnv.artifacts.GNVDefaultArtifact;
import de.intevation.gnv.artifacts.GNVProductArtifactFactory;
import de.intevation.gnv.artifacts.PreSettingArtifact;
import de.intevation.gnv.artifacts.fis.product.Product;
import de.intevation.gnv.artifacts.ressource.RessourceFactory;
import de.intevation.gnv.state.DefaultInputData;
import de.intevation.gnv.state.InputData;

/**
 * This artifact is used to handle to input/output at the beginning of a
 * parameterization when no product has been selected so far. After the user
 * having selected a product, this artifact is replaced by a concrete product
 * artifact.
 *
 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
 */
public class SelectProductArtifact extends GNVDefaultArtifact {

    /**
     * THE UID of this Class.
     */
    private static final long serialVersionUID = -7952357683127758677L;

    /**
     * Path to uuid.
     */
    public static final String XPATH_UUID = "art:action/art:uuid/@value";

    /**
     * Path to hash.
     */
    public static final String XPATH_HASH = "art:action/art:hash/@value";

    /**
     * Path to selected product.
     */
    public static final String XPATH_INPUT_DATA_VALUE =
        "art:action/art:data/art:input[@name='product']/@value";

    /**
     * Path to parameters required by the factory.
     */
    public static final String XPATH_SETUP_PARAMETER_NODES =
        "/art:action/art:factory/art:parameter";

    public static final String XFORM_URL    = "http://www.w3.org/2002/xforms";

    /**
     * Prefix used in the user interface description part of the describe
     * document.
     */
    public static final String XFORM_PREFIX = "xform";

    private static Logger log = Logger.getLogger(SelectProductArtifact.class);

    private Map      products;
    private Product  current;
    private Artifact artifact;
    private String   name;

    private Map<String, InputData> preSettings = null;

    /**
     * Constructor.
     */
    public SelectProductArtifact() {
        super();
    }


    /**
     * Initialize this artifact and parse all required information from <code>
     * data</code> document.
     *
     * @param identifier
     * @param factory
     * @param context
     * @param data
     */
    @Override
    public void setup(
        String          identifier,
        ArtifactFactory factory,
        Object          context,
        Document        data) {
        log.debug("SelectProductArtifact.setup()");
        super.setup(identifier, factory, context,data);
        this.name = factory.getName();

        // Read the Parameters that should be used for the setup from the
        // Data-XML.Document.
        NodeList parameterNodes = (NodeList) XMLUtils.xpath(data,
                XPATH_SETUP_PARAMETER_NODES,
                XPathConstants.NODESET,
                ArtifactNamespaceContext.INSTANCE);
        if (parameterNodes != null && parameterNodes.getLength() > 0){
            this.preSettings = new HashMap<String, InputData>();
            for (int i = 0; i < parameterNodes.getLength(); i++){
                Element parameterNode = (Element)parameterNodes.item(i);
                String name = parameterNode.getAttribute("name");
                String value = parameterNode.getAttribute("value");
                log.debug("Name:  "+name);
                log.debug("Value: "+value);
                InputData inputData = this.preSettings.get(name);
                if (inputData == null){
                    inputData = new DefaultInputData(name, value);
                    this.preSettings.put(name, inputData);
                }else{
                    inputData.concartValue(value);
                }
            }
        }

    }


    /**
     *
     * @param products Insert a bunch of products.
     */
    public void setProducts(Map products) {
        this.products = products;
    }


    /**
     * Search for a selected product and create a new concrecte product artifact
     * with this information.
     *
     * @param target Document which contains the selected product.
     * @param context CallContext.
     * @return Error or success message.
     */
    @Override
    public Document feed(Document target, CallContext context) {
        log.debug("SelectProductArtifact.feed()");

        if (artifact == null) {
            Document document    = XMLUtils.newDocument();
            String   productName = XMLUtils.xpathString(
                target,
                XPATH_INPUT_DATA_VALUE,
                ArtifactNamespaceContext.INSTANCE
            );

            current = (Product) products.get(productName);

            String reportNode = null;
            String resultNode = null;
            String msg        = null;

            if (current != null) {
                reportNode = "result";
                resultNode = "success";
                msg        = "Feed was successfully. New Artifact created.";
            }
            else {
                reportNode = "exceptionreport";
                resultNode = "exception";
                msg        = "Product does not exist.";
            }

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

            Element report  = creator.create(reportNode);
            Element success = creator.create(resultNode);
            success.setTextContent(msg);
            report.appendChild(success);
            document.appendChild(report);

            return document;
        }
        else {
            return artifact.feed(target, context);
        }
    }


    /**
     * If {@link #feed(org.w3c.dom.Document, de.intevation.artifacts.CallContext)}
     * was sucessfully called before, this artifact is replaced with a concrete
     * product artifact.
     *
     * @param target The advance document.
     * @param context The CallContext.
     * @return a document with an error or success message.
     */
    @Override
    public Document advance(Document target, CallContext context) {
        log.debug("SelectProductArtifact.advance()");

        if (artifact != null) {
            Document result = artifact.advance(target, context);
            context.putContextValue(ProxyArtifact.REPLACE_PROXY, artifact);
            return result;
        }

        Document result = XMLUtils.newDocument();
        if (current == null) {
            // artifact needs to be feeded first
            String msg = "Artifact is not configured properly. Call 'feed' fist.";
            log.error(msg);

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

            Element report = creator.create("exceptionreport");
            Element exception = creator.create("exception");
            exception.setTextContent(msg);
            report.appendChild(exception);
            result.appendChild(report);

            return result;
        }

        String uuid = XMLUtils.xpathString(
            target, XPATH_UUID, ArtifactNamespaceContext.INSTANCE
        );

        String hash = XMLUtils.xpathString(
            target, XPATH_HASH, ArtifactNamespaceContext.INSTANCE
        );

        // fetch ArtifactFactory from context and create a new Artifact
        ArtifactFactory factory = context.getDatabase()
            .getInternalArtifactFactory(this.name);
        factory                 = ((GNVProductArtifactFactory)factory)
            .getArtifactFactoryByName(current.getName());
        artifact                = factory.createArtifact(uuid, context, null);


        if (this.preSettings != null && artifact instanceof PreSettingArtifact){
            ((PreSettingArtifact)artifact).setPreSettings(this.preSettings);
        }

        artifact.feed(feedDocument(uuid, hash), context);

        result = ((GNVArtifactBase) artifact).initialize(context);
        if (artifact instanceof GNVArtifactBase) {
            ((GNVArtifactBase) artifact).setProduct(current);
        }
        context.putContextValue(ProxyArtifact.REPLACE_PROXY, artifact);
        return result;
    }


    /**
     * Create a describe document including the user interface description. The
     * user gets the choice to select a product supported by the current fis.
     *
     * @param data The describe document.
     * @param context The CallContext.
     * @return A document with an error or success message.
     */
    @Override
    public Document describe(Document data, CallContext context) {
        log.debug("SelectProductArtifact.describe()");

        // create root node
        Document document               = XMLUtils.newDocument();
        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
            document,
            ArtifactNamespaceContext.NAMESPACE_URI,
            ArtifactNamespaceContext.NAMESPACE_PREFIX
        );

        Element rootNode = creator.create("result");
        Element typeNode = creator.create("type");
        creator.addAttr(typeNode, "name", "describe");
        rootNode.appendChild(typeNode);

        Element uuidNode = creator.create("uuid");
        creator.addAttr(uuidNode, "value", super.identifier);
        rootNode.appendChild(uuidNode);

        Element hashNode = creator.create("hash");
        creator.addAttr(hashNode, "value", hash());
        rootNode.appendChild(hashNode);

        // create output node
        Element out = creator.create("outputs");
        rootNode.appendChild(out);

        // create current state
        Element state = creator.create("state");
        creator.addAttr(state, "name", "choose-product");
        creator.addAttr(state, "description", "Auswahl des Produktes.");
        rootNode.appendChild(state);

        // create reachable states
        Element rStates = creator.create("reachable-states");
        appendProducts(document, rStates, context);
        rootNode.appendChild(rStates);

        // create model
        Element model = creator.create("model");
        Element input = creator.create("input");
        creator.addAttr(input, "name", "product");
        creator.addAttr(input, "type", "String");
        model.appendChild(input);
        rootNode.appendChild(model);

        // create ui
        Element ui         = creator.create("ui");
        Element staticNode = creator.create("static");
        Element dynamic    = creator.create("dynamic");

        appendFis(document, staticNode, context, this.name);
        appendSelectProducts(document, dynamic, context.getMeta());
        ui.appendChild(staticNode);
        ui.appendChild(dynamic);
        rootNode.appendChild(ui);

        document.appendChild(rootNode);

        return document;
    }


    /**
     *
     * @param document
     * @param out
     * @param context
     * @throws IOException
     */
    @Override
    public void out(Document document, OutputStream out, CallContext context)
    throws IOException
    {
        log.debug("SelectProductArtifact.out()");
        if (artifact != null) {
            artifact.out(document, out, context);
        }
    }


    /**
     * Append products to the describe document.
     *
     * @param document The describe document.
     * @param parent The node the products should be appended to.
     * @param context The CallContext object.
     */
    protected void appendProducts(
        Document document,
        Node     parent,
        Object   context
    ) {
        if (products != null && !products.isEmpty()){
            Iterator iter = products.values().iterator();

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

            while(iter.hasNext()) {
                Product prod = (Product) iter.next();
                String  name = prod.getName();

                Element current = creator.create("state");
                creator.addAttr(current, "name", name);
                creator.addAttr(current, "description", name);
                parent.appendChild(current);
            }
        }
    }


    /**
     * Append the product select box to the user interface description of the
     * describe document.
     *
     * @param document The describe document.
     * @param node The node the products should be appended to.
     * @param callMeta The CallMeta object.
     */
    protected void appendSelectProducts(
        Document document,
        Node     node,
        CallMeta callMeta
    ) {
        RessourceFactory ressource = RessourceFactory.getInstance();

        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
            document,
            XFORM_URL,
            XFORM_PREFIX
        );

        String  selectboxName = "product";
        Element selectNode    = creator.create("select1");
        creator.addAttr(selectNode, "ref", selectboxName);

        Element lableNode = creator.create("label");
        lableNode.setTextContent(ressource.getRessource(callMeta.getLanguages(),
                selectboxName,
                selectboxName
            )
        );

        Element choiceNode = creator.create("choices");
        selectNode.appendChild(lableNode);
        selectNode.appendChild(choiceNode);
        if (products != null && !products.isEmpty()){
            Iterator it = products.values().iterator();
            while (it.hasNext()) {
                Product p               = (Product) it.next();
                Element itemNode        = creator.create("item");
                Element choiceLableNode = creator.create("label");
                choiceLableNode.setTextContent(ressource.getRessource(
                    callMeta.getLanguages(),
                    p.getName(),
                    p.getName()
                ));
                itemNode.appendChild(choiceLableNode);

                Element choiceValueNode = creator.create("value");
                choiceValueNode.setTextContent(p.getName());
                itemNode.appendChild(choiceValueNode);
                choiceNode.appendChild(itemNode);
            }
        }

        node.appendChild(selectNode);
    }


    /**
     * Create a feed document.
     *
     * @param uuid The UUID of the current artifact.
     * @param hash The hash of the current artifact.
     * @return the feed document.
     */
    protected Document feedDocument(String uuid, String hash) {
        Document document = XMLUtils.newDocument();

        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
            document,
            ArtifactNamespaceContext.NAMESPACE_URI,
            ArtifactNamespaceContext.NAMESPACE_PREFIX
        );
        Element  rootNode = creator.create("action");

        Element typeNode = creator.create("type");
        creator.addAttr(typeNode, "name", "feed");
        rootNode.appendChild(typeNode);

        Element uuidNode = creator.create("uuid");
        creator.addAttr(uuidNode, "value", uuid);
        rootNode.appendChild(uuidNode);

        Element hashNode = creator.create("hash");
        creator.addAttr(hashNode, "value", hash);
        rootNode.appendChild(hashNode);

        Element dataNode = creator.create("data");
        rootNode.appendChild(dataNode);

        Collection<InputData> parameter = this.current.getParameter();
        if (parameter != null) {
            Iterator<InputData> parameterIt = parameter.iterator();

            while (parameterIt.hasNext()) {
                InputData inputData = parameterIt.next();

                Element inputNode = creator.create("input");
                creator.addAttr(inputNode, "name", inputData.getName());
                creator.addAttr(inputNode, "value", inputData.getValue());
                dataNode.appendChild(inputNode);
            }
        }
        document.appendChild(rootNode);
        return document;
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org