view gnv-artifacts/src/main/java/de/intevation/gnv/artifacts/GNVArtifactBase.java @ 469:62fc63d0f71d

Added a new State in Product Verticalprofile in Timeseriespoints. Now it will be displayed the Years where measurements happened and than only the dates of the chosen Year will be fetched and displayed. gnv-artifacts/trunk@532 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Tim Englich <tim.englich@intevation.de>
date Tue, 12 Jan 2010 12:42:53 +0000
parents 70df44021a9f
children b7bb66440cc8
line wrap: on
line source
/**
 *
 */
package de.intevation.gnv.artifacts;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
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.Config;
import de.intevation.artifactdatabase.DefaultArtifact;
import de.intevation.artifactdatabase.XMLUtils;
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.context.GNVArtifactContext;
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;
import de.intevation.gnv.state.InputValue;
import de.intevation.gnv.state.OutputMode;
import de.intevation.gnv.state.OutputState;
import de.intevation.gnv.state.State;
import de.intevation.gnv.state.StateFactory;
import de.intevation.gnv.state.exception.StateException;
import de.intevation.gnv.transition.Transition;
import de.intevation.gnv.transition.TransitionFactory;
import de.intevation.gnv.utils.ArtifactXMLUtilities;

/**
 * @author Tim Englich <tim.englich@intevation.de>
 * @author Ingo Weinzierl <ingo.weinzierl@intevation.de>
 * 
 */
public abstract class GNVArtifactBase extends DefaultArtifact {
    /**
     * the logger, used to log exceptions and additonaly information
     */
    private static Logger log = Logger.getLogger(GNVArtifactBase.class);
    /**
     * The UID of this Class
     */
    private static final long serialVersionUID = -8907096744400741458L;

    /**
     * The Identifier for the Replacement of the Artifactname
     */
    public static final String XPATH_IDENTIFIER_REPLACE = "IDENTIFIER";

    /**
     * The XPATH to the XML-Fragment that should be used for the Configuration
     */
    public static final String XPATH_ARTIFACT_CONFIGURATION = "/artifact-database/artifacts/artifact[@name='"
                                                              + XPATH_IDENTIFIER_REPLACE
                                                              + "']";

    public static final String XPATH_STATIC_NODE = "/art:result/art:ui/art:static";

    public static final String XPATH_INPUT_DATA = "/art:action/art:data/art:input";

    public static final String XPATH_INCLUDE_UI = "/art:action/art:include-ui";

    public static final String XPATH_TARGET_NAME = "/art:action/art:target/@name";

    public static final String XPATH_OUTPUT_NAME = "/art:action/art:out/@name"; 

    public static final String XPATH_OUTPUT_PARAMS = "/art:action/art:out/art:params/art:input"; 

    /**
     * The current State
     */
    protected State current = null;

    /**
     * The States that can be used
     */
    protected Map<String, State> states = null;
    
    /**
     * The Transitions which can switch between the different States.
     */
    protected Collection<Transition> transitions = null;


    /**
     * The current product
     */
    protected Product product;

    /**
     * The Name of the Artifact
     */
    protected String name = null;

    private ArtifactXMLUtilities xmlUtilities = new ArtifactXMLUtilities();

    /**
     * Constructor
     */
    public GNVArtifactBase() {
        super();
    }

    /**
     * @see de.intevation.artifactdatabase.DefaultArtifact#advance(org.w3c.dom.Document,
     *      de.intevation.artifacts.CallContext)
     */
    @Override
    public Document advance(Document target, CallContext context) {
        log.debug("GNVArtifactBase.advance");
        Document result = XMLUtils.newDocument();
        try {
            if (this.current != null) {
                String stateName = this.readStateName(target);
                log.debug("Statename: " + stateName);
                if (this.isStateCurrentlyReachable(stateName)) {
                    try {
                        State nextStep = this.states
                                .get(stateName);
                        // 1.Calculate Results
                        this.current.advance(super.identifier, context.getMeta());
                        // 2. Transfer Results
                        nextStep.putInputData(this.current.getInputData(), 
                                              super.identifier);
                        // 3. Switch to next State
                        this.current = nextStep;
                        
                        // 4. Initialize next Step
                        this.current.initialize(super.identifier, context.getMeta());
                        
                        result = new ArtifactXMLUtilities()
                                .createSuccessReport("Advance success",
                                        XMLUtils.newDocument());
                    } catch (StateException e) {
                        log.error(e, e);
                        result = new ArtifactXMLUtilities()
                                .createExceptionReport(e
                                        .getLocalizedMessage(), XMLUtils
                                        .newDocument());
                    }
                } else {
                    String msg = "Statetransition is not supported";
                    log.error(msg);
                    result = new ArtifactXMLUtilities().createExceptionReport(
                            msg, XMLUtils.newDocument());
                }
            } else {
                String msg = "No State activated.";
                log.error(msg);
                result = new ArtifactXMLUtilities().createExceptionReport(msg,
                        XMLUtils.newDocument());
            }
        } catch (Exception e) {
            log.error(e, e);
            result = new ArtifactXMLUtilities().createExceptionReport(e
                    .getLocalizedMessage(), XMLUtils.newDocument());
        }
        return result;
    }
    
    
    private boolean isStateCurrentlyReachable(String stateid){
        log.debug("GNVArtifactBase.isStateCurrentlyReachable "+stateid);
        Iterator<Transition> it = this.transitions.iterator();
        String from = this.current.getID();
        while (it.hasNext()){
            Transition transition = it.next();
            if (transition.getFrom().equals(from)){
                if (transition.getTo().equals(stateid) && transition.isValid(this.current)){
                    return true;
                }
            }
        }
        return false;
    }
    
    public Document initialize (CallContext context) {
        Document result = XMLUtils.newDocument();
        try {
            this.current.initialize(super.identifier, context.getMeta());
            result = new ArtifactXMLUtilities()
            .createSuccessReport("Initialize success",
                    XMLUtils.newDocument());
        } catch (StateException e) {
            log.error(e,e);
            result = new ArtifactXMLUtilities().createExceptionReport(e
                    .getLocalizedMessage(), XMLUtils.newDocument());
        }
        return result;
    }

    protected String readStateName(Document document) {
        String returnValue = XMLUtils.xpathString(
            document, XPATH_TARGET_NAME, ArtifactNamespaceContext.INSTANCE);
        return returnValue;
    }

    protected Node getConfigurationFragment(Document document) {
        log.debug("GNVArtifactBase.getConfigurationFragment");
        String xpathQuery = XPATH_ARTIFACT_CONFIGURATION.replaceAll(
                XPATH_IDENTIFIER_REPLACE, this.name);
        log.debug(xpathQuery);
        
        Element configurationNode = (Element)Config.getNodeXPath(document, xpathQuery);
        
        String link = configurationNode.getAttribute("xlink:href");
        if (link != null ){
            String absolutFileName = Config.replaceConfigDir(link);
            configurationNode = (Element)new ArtifactXMLUtilities().readConfiguration(absolutFileName);
        }
        
        return configurationNode;
    }

    /**
     * @see de.intevation.artifactdatabase.DefaultArtifact#feed(org.w3c.dom.Document,
     *      de.intevation.artifacts.CallContext)
     */
    @Override
    public Document feed(Document target, CallContext context) {
        log.debug("GNVArtifactBase.feed");
        Document result = XMLUtils.newDocument();
        try {
            if (this.current != null) {
                Collection<InputData> inputData = this.parseInputData(
                    target,
                    XPATH_INPUT_DATA);

                if (!inputData.isEmpty()){
                    this.current.putInputData(inputData, super.identifier);
                    result = new ArtifactXMLUtilities().createSuccessReport(
                            "Feed success", XMLUtils.newDocument());
                }else{
                    String msg = "No Inputdata given. Please select at least one Entry.";
                    log.warn(msg);
                    result = new ArtifactXMLUtilities().createExceptionReport(msg,
                            XMLUtils.newDocument());
                }
            } else {
                String msg = "No State instantiated";
                log.warn(msg);
                result = new ArtifactXMLUtilities().createExceptionReport(msg,
                        XMLUtils.newDocument());
            }
        } catch (StateException e) {
            log.error(e, e);
            result = new ArtifactXMLUtilities().createExceptionReport(e
                    .getLocalizedMessage(), XMLUtils.newDocument());
        }
        return result;
    }


    /**
     * @see de.intevation.artifactdatabase.DefaultArtifact#describe(org.w3c.dom.Document, de.intevation.artifacts.CallContext)
     */
    @Override
    public Document describe(Document data, CallContext context) {
        log.debug("GNVArtifactBase.describe");

        Document document = createDescibeOutput(
            context.getMeta(),
            identifier,
            getIncludeUIFromDocument(data)
        );

        // insert node for rendering product field
        Element staticNode = (Element) XMLUtils.xpath(
            document,
            XPATH_STATIC_NODE,
            XPathConstants.NODE,
            ArtifactNamespaceContext.INSTANCE
        );

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

        if (staticNode != null) {
            Element staticUI = createSelectBox(creator, document, context);
            staticNode.insertBefore(staticUI, staticNode.getFirstChild());
        }

        return document;
    }

    /**
     * @see de.intevation.artifactdatabase.DefaultArtifact#setup(java.lang.String,
     *      java.lang.Object)
     */
    @Override
    public void setup(String identifier, ArtifactFactory factory, Object context) {
        log.debug("GNVArtifactBase.setup");
        super.setup(identifier, factory, context);

        Object localContext = context;
        if (context instanceof CallContext) {
            localContext = ((CallContext) context).globalContext();

        }

        if (localContext instanceof GNVArtifactContext) {
            GNVArtifactContext gnvContext = (GNVArtifactContext) localContext;
            Document doc = gnvContext.getConfig();
            Node artifactNode = this.getConfigurationFragment(doc);
                        
            NodeList stateList = Config.getNodeSetXPath(artifactNode,
                    "states/state");
            this.states = new HashMap<String, State>(stateList
                    .getLength());
            for (int i = 0; i < stateList.getLength(); i++) {
                State tmpState = StateFactory.getInstance()
                        .createState(stateList.item(i));
                if (tmpState != null) {
                    this.states.put(tmpState.getID(), tmpState);
                    if (this.current == null) {
                        this.current = tmpState;
                    }
                }
            }
            
            NodeList transitionList = Config.getNodeSetXPath(artifactNode,
            "states/transition");
            this.transitions = new ArrayList<Transition>(transitionList.getLength());
            for (int i = 0; i < transitionList.getLength(); i++) {
                Transition tmpTransition = TransitionFactory.getInstance()
                        .createTransition(transitionList.item(i));
                if (tmpTransition != null) {
                    this.transitions.add(tmpTransition);
                }
            }

        }
    }
    

    protected Document createDescibeOutput(CallMeta callMeta, String uuid, boolean incudeUI) {
        log.debug("GNVArtifactBase.createDescibeOutput");
        Document document = XMLUtils.newDocument();
        
        XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
            document,
            ArtifactNamespaceContext.NAMESPACE_URI,
            ArtifactNamespaceContext.NAMESPACE_PREFIX
        );
        Element rootNode = this.createRootNode(document);
        this.createHeader(creator, rootNode, document, "describe");
        this.createOutputs(creator, rootNode, document);
        this.createCurrentState(creator, rootNode, document);
        this.createReachableStates(creator, rootNode, document);
        this.createModel(creator, rootNode, document);
        if (incudeUI){
            this.createUserInterface(creator, rootNode, document, callMeta, uuid);
        }

        return document;
    }
    
    protected boolean getIncludeUIFromDocument(Document document){
        String value = XMLUtils.xpathString(
            document, XPATH_INCLUDE_UI, ArtifactNamespaceContext.INSTANCE);

        boolean includeUI = false;
        if (value != null){
            includeUI = Boolean.parseBoolean(value);
        }
        log.debug("INCLUDE UI? " + includeUI);
        return includeUI;
    }

    protected Element createRootNode(Document document) {
        Element rootNode = xmlUtilities.createArtifactElement(document,
                "result");
        document.appendChild(rootNode);
        return rootNode;
    }

    protected void createHeader(
        XMLUtils.ElementCreator creator,
        Element                 parent,
        Document                document,
        String                  documentType
    ) { 
        Element typeNode = creator.create("type");
        creator.addAttr(typeNode, "name", documentType);
        parent.appendChild(typeNode);

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

        Element hashNode = creator.create("hash");
        creator.addAttr(hashNode, "value", this.hash());
        parent.appendChild(hashNode);
    }

    protected Element createSelectBox(
        XMLUtils.ElementCreator creator,
        Document                document,
        CallContext             context
    ) {
        RessourceFactory resource = RessourceFactory.getInstance();
        CallMeta callMeta         = (CallMeta) context.getMeta();
        String productName        = product.getName(); 

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

        Element labelNode = creator.create("label");
        labelNode.setTextContent(
            resource.getRessource(callMeta.getLanguages(), "product", "product")
        );

        Element choicesNode = creator.create("choices");

        Element itemNode = creator.create("item");
        creator.addAttr(itemNode, "selected", "true");

        Element choiceLabel = creator.create("label");
        choiceLabel.setTextContent(resource.getRessource(
            callMeta.getLanguages(),
            productName,
            productName
        ));

        Element choiceValue = creator.create("value");
        choiceValue.setTextContent(productName);

        itemNode.appendChild(choiceLabel);
        itemNode.appendChild(choiceValue);
        choicesNode.appendChild(itemNode);

        selectNode.appendChild(labelNode);
        selectNode.appendChild(choicesNode);

        return selectNode;
    }

    protected void createReachableStates(
        XMLUtils.ElementCreator creator,
        Element                 parent,
        Document                document
    ) {
        Element stateNode = creator.create("reachable-states");
        if (this.current != null) {
            Iterator<Transition> transitions = this.transitions.iterator();
            while (transitions.hasNext()) {
                Transition tmpTransition = transitions.next();
                if (tmpTransition.getFrom().equals(current.getID()) && 
                    tmpTransition.isValid(this.current)){
                    Element currentNode = creator.create("state");
                    creator.addAttr(currentNode, "name", tmpTransition.getTo());
                    log.debug("Reachable State: " + tmpTransition.getTo());
                    creator.addAttr(
                        currentNode,
                        "description",
                        this.states.get(tmpTransition.getTo()).getDescription());
                    stateNode.appendChild(currentNode);
                }
            }
        }
        parent.appendChild(stateNode);
    }

    protected void createCurrentState(
        XMLUtils.ElementCreator creator,
        Element                 parent,
        Document                document
    ) {
        Element stateNode = creator.create("state");
        creator.addAttr(stateNode, "name", this.current.getID());
        creator.addAttr(stateNode, "description", this.current.getDescription());
        parent.appendChild(stateNode);
    }

    protected void createModel(
        XMLUtils.ElementCreator creator,
        Element                 parent,
        Document                document
    ) {
        Element modelNode = creator.create("model");
        if (this.current != null) {
            Collection<InputValue> inputValues = this.current
                    .getRequiredInputValues();
            if (inputValues != null) {
                Iterator<InputValue> it = inputValues.iterator();
                while (it.hasNext()) {
                    InputValue inputValue = it.next();
                    Element inputNode = creator.create("input");
                    creator.addAttr(inputNode, "name", inputValue.getName());
                    creator.addAttr(inputNode, "type", inputValue.getType());
                    modelNode.appendChild(inputNode);
                }
            }
        }
        parent.appendChild(modelNode);
    }

    protected void createUserInterface(
        XMLUtils.ElementCreator creator,
        Element                 parent,
        Document                document,
        CallMeta                callMeta,
        String uuid
    ) {
        Element uiNode = creator.create("ui");

        if (this.current != null) {
            this.current.describe(document, uiNode, callMeta, uuid);
        }

        parent.appendChild(uiNode);
    }

    protected void createOutputs(
        XMLUtils.ElementCreator creator,
        Element                 parent,
        Document                document
    ) {
        log.debug("GNVArtifactBase.createOutputs");
        Element outputsNode = creator.create("outputs");
        if (this.current instanceof OutputState) {
            Collection<OutputMode> outputModes = ((OutputState) this.current)
                    .getOutputModes();
            if (outputModes != null) {
                Iterator<OutputMode> it = outputModes.iterator();
                while (it.hasNext()) {
                    OutputMode outputMode = it.next();
                    log.debug("Write Outputnode for " + outputMode.toString());
                    Element outputModeNode = creator.create("output");
                    creator.addAttr(
                        outputModeNode, "name", outputMode.getName());
                    creator.addAttr(
                        outputModeNode, "description", outputMode.getDescription());
                    creator.addAttr(
                        outputModeNode, "mime-type", outputMode.getMimeType());
                    outputsNode.appendChild(outputModeNode);

                    Collection<InputValue> inputParameters = outputMode
                            .getInputParameters();
                    if (inputParameters != null) {
                        Element inputParametersNode = creator.create("parameter");
                        outputModeNode.appendChild(inputParametersNode);
                        Iterator<InputValue> it2 = inputParameters.iterator();
                        while (it2.hasNext()) {
                            InputValue inputValue = it2.next();
                            Element inputParameterNode =
                                creator.create("parameter");
                            creator.addAttr(
                                inputParameterNode, "name", inputValue.getName());
                            creator.addAttr(
                                inputParameterNode, "type", inputValue.getType());
                            creator.addAttr(
                                inputParameterNode, "value", inputValue.getDefaultValue());
                            inputParametersNode.appendChild(inputParameterNode);
                        }
                    }
                }
            } else {
                log.warn("No Outputmodes given.");
            }
        }
        parent.appendChild(outputsNode);
    }

    protected Collection<InputData> parseInputData(Document document,
                                                   String xPath) {
        HashMap<String, InputData> returnValue = null;

        NodeList inputElemets = (NodeList) XMLUtils.xpath(document, xPath,
                XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE);
        if (inputElemets != null) {
            returnValue = new HashMap<String, InputData>();

            for (int i = 0; i < inputElemets.getLength(); i++) {
                Element inputDataNode = (Element)inputElemets.item(i);
                String name = inputDataNode.getAttribute("name");
                String value = inputDataNode.getAttribute("value");

                if (returnValue.containsKey(name)) {
                    InputData inputData = returnValue.get(name);
                    inputData.concartValue(value);
                    log.debug(inputData.toString());
                    returnValue.put(name, inputData);
                } else {
                    InputData inputData = new DefaultInputData(name, value);

                    returnValue.put(name, inputData);
                }
            }
        }
        return returnValue.values();
    }

    /**
     * @see de.intevation.artifactdatabase.DefaultArtifact#out(org.w3c.dom.Document,
     *      java.io.OutputStream, de.intevation.artifacts.CallContext)
     */
    @Override
    public void out(Document format, OutputStream outputStream,
                    CallContext context) throws IOException {
        log.debug("TGNVArtifactBase.out");
        try {

            if (current != null && current instanceof OutputState) {
                ((OutputState) current)
                        .out(format, this.parseInputData(
                                format, XPATH_OUTPUT_PARAMS),
                                outputStream, super.identifier, context);
            }
        } catch (StateException e) {
            log.error(e, e);
            throw new IOException(e.getMessage());
        }
    }

    protected String readOutputType(Document document) {
        String value = XMLUtils.xpathString(
            document, XPATH_OUTPUT_NAME, ArtifactNamespaceContext.INSTANCE);
        return value;
    }


    public void setProduct(Product product) {
        this.product = product;        
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:

http://dive4elements.wald.intevation.org