tim@52: /**
tim@52:  *
tim@52:  */
tim@52: package de.intevation.gnv.artifacts;
tim@52: 
tim@73: import java.io.IOException;
tim@73: import java.io.OutputStream;
tim@56: import java.util.Collection;
tim@52: import java.util.HashMap;
tim@54: import java.util.Iterator;
tim@52: import java.util.Map;
tim@52: 
tim@71: import javax.xml.xpath.XPathConstants;
tim@71: 
tim@52: import org.apache.log4j.Logger;
tim@52: import org.w3c.dom.Document;
tim@54: import org.w3c.dom.Element;
tim@52: import org.w3c.dom.Node;
tim@52: import org.w3c.dom.NodeList;
tim@52: 
tim@52: import de.intevation.artifactdatabase.Config;
tim@52: import de.intevation.artifactdatabase.DefaultArtifact;
tim@71: import de.intevation.artifactdatabase.XMLUtils;
tim@70: import de.intevation.artifacts.ArtifactFactory;
tim@70: import de.intevation.artifacts.ArtifactNamespaceContext;
tim@73: import de.intevation.artifacts.CallContext;
tim@117: import de.intevation.artifacts.CallMeta;
tim@52: import de.intevation.gnv.artifacts.context.GNVArtifactContext;
tim@57: import de.intevation.gnv.transition.DefaultInputData;
tim@57: import de.intevation.gnv.transition.InputData;
tim@56: import de.intevation.gnv.transition.InputValue;
tim@64: import de.intevation.gnv.transition.OutputMode;
tim@64: import de.intevation.gnv.transition.OutputTransition;
tim@52: import de.intevation.gnv.transition.Transition;
tim@52: import de.intevation.gnv.transition.TransitionFactory;
tim@57: import de.intevation.gnv.transition.exception.TransitionException;
tim@71: import de.intevation.gnv.utils.ArtifactXMLUtilities;
tim@52: 
tim@52: /**
tim@52:  * @author Tim Englich <tim.englich@intevation.de>
tim@171:  * 
tim@52:  */
tim@52: public abstract class GNVArtifactBase extends DefaultArtifact {
tim@52:     /**
tim@52:      * the logger, used to log exceptions and additonaly information
tim@52:      */
tim@52:     private static Logger log = Logger.getLogger(GNVArtifactBase.class);
tim@52:     /**
tim@52:      * The UID of this Class
tim@52:      */
tim@52:     private static final long serialVersionUID = -8907096744400741458L;
tim@171: 
tim@54:     /**
tim@54:      * The Identifier for the Replacement of the Artifactname
tim@54:      */
tim@52:     public static final String XPATH_IDENTIFIER_REPLACE = "IDENTIFIER";
tim@171: 
tim@52:     /**
tim@52:      * The XPATH to the XML-Fragment that should be used for the Configuration
tim@52:      */
tim@171:     public static final String XPATH_ARTIFACT_CONFIGURATION = "/artifact-database/artifacts/artifact[@name='"
tim@171:                                                               + XPATH_IDENTIFIER_REPLACE
tim@171:                                                               + "']";
tim@171: 
tim@54:     /**
tim@54:      * The current Transition
tim@54:      */
tim@52:     protected Transition current = null;
tim@171: 
tim@54:     /**
tim@54:      * The Transitions that can be used
tim@54:      */
tim@52:     protected Map<String, Transition> transitions = null;
tim@52: 
tim@54:     /**
tim@54:      * The Name of the Artifact
tim@54:      */
tim@52:     protected String name = null;
tim@171: 
tim@71:     private ArtifactXMLUtilities xmlUtilities = new ArtifactXMLUtilities();
tim@171: 
tim@52:     /**
tim@52:      * Constructor
tim@52:      */
tim@52:     public GNVArtifactBase() {
tim@52:         super();
tim@52:     }
tim@171: 
tim@58:     /**
tim@171:      * @see de.intevation.artifactdatabase.DefaultArtifact#advance(org.w3c.dom.Document,
tim@171:      *      de.intevation.artifacts.CallContext)
tim@58:      */
tim@58:     @Override
tim@73:     public Document advance(Document target, CallContext context) {
tim@89:         log.debug("GNVArtifactBase.advance");
tim@71:         Document result = XMLUtils.newDocument();
tim@88:         try {
tim@171:             if (this.current != null) {
tim@88:                 String transitionName = this.readTransitionName(target);
tim@171:                 log.debug("Transitionsname: " + transitionName);
tim@171:                 if (this.current.isTransitionReachable(transitionName)) {
tim@220:                     try {
tim@220:                         Transition nextStep = this.transitions
tim@220:                                 .get(transitionName);
tim@220:                         // 1.Ergebnisse Berechnen
tim@220:                         this.current.advance(super.identifier, context.getMeta());
tim@220:                         // 2. Ergebnisse �bergeben
tim@220:                         nextStep.putInputData(this.current.getInputData(), 
tim@220:                                               super.identifier);
tim@220:                         // 3. Umschalten auf neue Transistion
tim@220:                         this.current = nextStep;
tim@171:                         result = new ArtifactXMLUtilities()
tim@220:                                 .createSuccessReport("Advance success",
tim@220:                                         XMLUtils.newDocument());
tim@220:                     } catch (TransitionException e) {
tim@220:                         log.error(e, e);
tim@220:                         result = new ArtifactXMLUtilities()
tim@220:                                 .createExceptionReport(e
tim@220:                                         .getLocalizedMessage(), XMLUtils
tim@171:                                         .newDocument());
tim@58:                     }
tim@171:                 } else {
tim@88:                     String msg = "Transitions�bergang wird nicht unterst�tzt.";
tim@88:                     log.error(msg);
tim@171:                     result = new ArtifactXMLUtilities().createExceptionReport(
tim@171:                             msg, XMLUtils.newDocument());
tim@58:                 }
tim@171:             } else {
tim@88:                 String msg = "Kein Transitionsschritt aktiviert.";
tim@88:                 log.error(msg);
tim@171:                 result = new ArtifactXMLUtilities().createExceptionReport(msg,
tim@171:                         XMLUtils.newDocument());
tim@58:             }
tim@88:         } catch (Exception e) {
tim@171:             log.error(e, e);
tim@171:             result = new ArtifactXMLUtilities().createExceptionReport(e
tim@171:                     .getLocalizedMessage(), XMLUtils.newDocument());
tim@58:         }
tim@58:         return result;
tim@58:     }
tim@58: 
tim@58:     protected String readTransitionName(Document document) {
tim@171:         String returnValue = Config.getStringXPath(document,
tim@171:                 "action/target/@name");
tim@58:         return returnValue;
tim@58:     }
tim@58: 
tim@171:     protected Node getConfigurationFragment(Document document) {
tim@52:         log.debug("GNVArtifactBase.getConfigurationFragment");
tim@171:         String xpathQuery = XPATH_ARTIFACT_CONFIGURATION.replaceAll(
tim@171:                 XPATH_IDENTIFIER_REPLACE, this.name);
tim@52:         log.debug(xpathQuery);
tim@204:         
tim@204:         Element configurationNode = (Element)Config.getNodeXPath(document, xpathQuery);
tim@204:         
tim@204:         String link = configurationNode.getAttribute("xlink:href");
tim@204:         if (link != null ){
tim@204:             String absolutFileName = Config.replaceConfigDir(link);
tim@217:             configurationNode = (Element)new ArtifactXMLUtilities().readConfiguration(absolutFileName);
tim@204:         }
tim@204:         
tim@204:         return configurationNode;
tim@204:     }
tim@171: 
tim@52:     /**
tim@171:      * @see de.intevation.artifactdatabase.DefaultArtifact#feed(org.w3c.dom.Document,
tim@171:      *      de.intevation.artifacts.CallContext)
tim@57:      */
tim@57:     @Override
tim@73:     public Document feed(Document target, CallContext context) {
tim@89:         log.debug("GNVArtifactBase.feed");
tim@71:         Document result = XMLUtils.newDocument();
tim@57:         try {
tim@171:             if (this.current != null) {
tim@194:                 Collection<InputData> inputData = this.parseInputData(target,
tim@194:                                                                       "/action/data/input");
tim@194:                 if (!inputData.isEmpty()){
tim@208:                     this.current.putInputData(inputData, super.identifier);
tim@194:                     result = new ArtifactXMLUtilities().createSuccessReport(
tim@194:                             "Feed success", XMLUtils.newDocument());
tim@194:                 }else{
tim@194:                     String msg = "No Inputdata given. Please select at least one Entry.";
tim@194:                     log.warn(msg);
tim@194:                     result = new ArtifactXMLUtilities().createExceptionReport(msg,
tim@194:                             XMLUtils.newDocument());
tim@194:                 }
tim@171:             } else {
tim@89:                 String msg = "No Transition instantiated";
tim@89:                 log.warn(msg);
tim@171:                 result = new ArtifactXMLUtilities().createExceptionReport(msg,
tim@171:                         XMLUtils.newDocument());
tim@57:             }
tim@57:         } catch (TransitionException e) {
tim@171:             log.error(e, e);
tim@171:             result = new ArtifactXMLUtilities().createExceptionReport(e
tim@171:                     .getLocalizedMessage(), XMLUtils.newDocument());
tim@57:         }
tim@57:         return result;
tim@57:     }
tim@171: 
tim@57:     /**
tim@171:      * @see de.intevation.artifactdatabase.DefaultArtifact#setup(java.lang.String,
tim@171:      *      java.lang.Object)
tim@52:      */
tim@52:     @Override
tim@70:     public void setup(String identifier, ArtifactFactory factory, Object context) {
tim@52:         log.debug("GNVArtifactBase.setup");
tim@70:         super.setup(identifier, factory, context);
tim@171: 
tim@77:         Object localContext = context;
tim@171:         if (context instanceof CallContext) {
tim@171:             localContext = ((CallContext) context).globalContext();
tim@171: 
tim@77:         }
tim@171: 
tim@171:         if (localContext instanceof GNVArtifactContext) {
tim@171:             GNVArtifactContext gnvContext = (GNVArtifactContext) localContext;
tim@52:             Document doc = gnvContext.getConfig();
tim@52:             Node artifactNode = this.getConfigurationFragment(doc);
tim@204:                         
tim@171:             NodeList transitionList = Config.getNodeSetXPath(artifactNode,
tim@171:                     "transitions/transition");
tim@171:             this.transitions = new HashMap<String, Transition>(transitionList
tim@171:                     .getLength());
tim@171:             for (int i = 0; i < transitionList.getLength(); i++) {
tim@171:                 Transition tmpTransition = TransitionFactory.getInstance()
tim@171:                         .createTransition(transitionList.item(i));
tim@171:                 if (tmpTransition != null) {
tim@52:                     this.transitions.put(tmpTransition.getID(), tmpTransition);
tim@171:                     if (this.current == null) {
tim@52:                         this.current = tmpTransition;
tim@52:                     }
tim@52:                 }
tim@52:             }
tim@171: 
tim@52:         }
tim@52:     }
tim@171: 
tim@222:     protected Document createDescibeOutput(CallMeta callMeta, String uuid, boolean incudeUI) {
tim@54:         log.debug("GNVArtifactBase.createDescibeOutput");
tim@71:         Document document = XMLUtils.newDocument();
tim@171:         Element rootNode = this.createRootNode(document);
tim@54:         this.createHeader(rootNode, document, "describe");
tim@59:         this.createOutputs(rootNode, document);
tim@54:         this.createCurrentState(rootNode, document);
tim@54:         this.createReachableStates(rootNode, document);
tim@54:         this.createModel(rootNode, document);
tim@222:         if (incudeUI){
tim@222:             this.createUserInterface(rootNode, document, callMeta, uuid);
tim@222:         }
tim@54:         return document;
tim@54:     }
tim@222:     
tim@222:     protected boolean getIncludeUIFromDocument(Document document){
tim@222:         String value = Config.getStringXPath(document, "action/include-ui");
tim@222:         boolean includeUI = false;
tim@222:         if (value != null){
tim@222:             includeUI = Boolean.parseBoolean(value);
tim@222:         }
tim@222:         return includeUI;
tim@222:     }
tim@171: 
tim@171:     protected Element createRootNode(Document document) {
tim@171:         Element rootNode = xmlUtilities.createArtifactElement(document,
tim@171:                 "result");
tim@54:         document.appendChild(rootNode);
tim@54:         return rootNode;
tim@54:     }
tim@171: 
tim@171:     protected void createHeader(Element parent, Document document,
tim@171:                                 String documentType) {
tim@171:         Element typeNode = xmlUtilities.createArtifactElement(document, "type");
tim@54:         typeNode.setAttribute("name", documentType);
tim@54:         parent.appendChild(typeNode);
tim@171: 
tim@171:         Element uuidNode = xmlUtilities.createArtifactElement(document, "uuid");
tim@54:         uuidNode.setAttribute("value", super.identifier);
tim@54:         parent.appendChild(uuidNode);
tim@171: 
tim@171:         Element hashNode = xmlUtilities.createArtifactElement(document, "hash");
tim@54:         hashNode.setAttribute("value", this.hash());
tim@54:         parent.appendChild(hashNode);
tim@89:     }
tim@54: 
tim@171:     protected void createReachableStates(Element parent, Document document) {
tim@171:         Element stateNode = xmlUtilities.createArtifactElement(document,
tim@171:                 "reachable-states");
tim@171:         if (this.current != null) {
tim@171:             Iterator<String> states = this.current.reachableTransitions()
tim@171:                     .iterator();
tim@171:             while (states.hasNext()) {
tim@54:                 String value = states.next();
tim@171:                 Element currentNode = xmlUtilities.createArtifactElement(
tim@171:                         document, "state");
tim@54:                 currentNode.setAttribute("name", value);
tim@171:                 log.debug("Reachable State: " + value);
tim@171:                 currentNode.setAttribute("description", transitions.get(value)
tim@171:                         .getDescription());
tim@54:                 stateNode.appendChild(currentNode);
tim@54:             }
tim@54:         }
tim@54:         parent.appendChild(stateNode);
tim@54:     }
tim@171: 
tim@171:     protected void createCurrentState(Element parent, Document document) {
tim@171:         Element stateNode = xmlUtilities.createArtifactElement(document,
tim@171:                 "state");
tim@54:         stateNode.setAttribute("name", this.current.getID());
tim@54:         stateNode.setAttribute("description", this.current.getDescription());
tim@54:         parent.appendChild(stateNode);
tim@54:     }
tim@171: 
tim@171:     protected void createModel(Element parent, Document document) {
tim@171:         Element modelNode = xmlUtilities.createArtifactElement(document,
tim@171:                 "model");
tim@171:         if (this.current != null) {
tim@171:             Collection<InputValue> inputValues = this.current
tim@171:                     .getRequiredInputValues();
tim@171:             if (inputValues != null) {
tim@56:                 Iterator<InputValue> it = inputValues.iterator();
tim@171:                 while (it.hasNext()) {
tim@56:                     InputValue inputValue = it.next();
tim@171:                     Element inputNode = xmlUtilities.createArtifactElement(
tim@171:                             document, "input");
tim@56:                     inputNode.setAttribute("name", inputValue.getName());
tim@56:                     inputNode.setAttribute("type", inputValue.getType());
tim@56:                     modelNode.appendChild(inputNode);
tim@56:                 }
tim@56:             }
tim@56:         }
tim@54:         parent.appendChild(modelNode);
tim@54:     }
tim@171: 
tim@171:     protected void createUserInterface(Element parent, Document document,
tim@207:                                        CallMeta callMeta, String uuid) {
tim@171:         Element uiNode = xmlUtilities.createArtifactElement(document, "ui");
tim@171: 
tim@171:         if (this.current != null) {
tim@207:             this.current.describe(document, uiNode, callMeta, uuid);
tim@61:         }
tim@171: 
tim@54:         parent.appendChild(uiNode);
tim@54:     }
tim@171: 
tim@171:     protected void createOutputs(Element parent, Document document) {
tim@64:         log.debug("GNVArtifactBase.createOutputs");
tim@171:         Element outputsNode = xmlUtilities.createArtifactElement(document,
tim@171:                 "outputs");
tim@171:         if (this.current instanceof OutputTransition) {
tim@171:             Collection<OutputMode> outputModes = ((OutputTransition) this.current)
tim@171:                     .getOutputModes();
tim@171:             if (outputModes != null) {
tim@64:                 Iterator<OutputMode> it = outputModes.iterator();
tim@171:                 while (it.hasNext()) {
tim@64:                     OutputMode outputMode = it.next();
tim@171:                     log.debug("Write Outputnode for " + outputMode.toString());
tim@171:                     Element outputModeNode = xmlUtilities
tim@171:                             .createArtifactElement(document, "output");
tim@64:                     outputModeNode.setAttribute("name", outputMode.getName());
tim@171:                     outputModeNode.setAttribute("description", outputMode
tim@171:                             .getDescription());
tim@171:                     outputModeNode.setAttribute("mime-type", outputMode
tim@171:                             .getMimeType());
tim@64:                     outputsNode.appendChild(outputModeNode);
tim@171: 
tim@171:                     Collection<InputValue> inputParameters = outputMode
tim@171:                             .getInputParameters();
tim@171:                     if (inputParameters != null) {
tim@171:                         Element inputParametersNode = xmlUtilities
tim@171:                                 .createArtifactElement(document, "parameter");
tim@91:                         outputModeNode.appendChild(inputParametersNode);
tim@91:                         Iterator<InputValue> it2 = inputParameters.iterator();
tim@171:                         while (it2.hasNext()) {
tim@91:                             InputValue inputValue = it2.next();
tim@171:                             Element inputParameterNode = xmlUtilities
tim@171:                                     .createArtifactElement(document,
tim@171:                                             "parameter");
tim@91:                             inputParametersNode.appendChild(inputParameterNode);
tim@171:                             inputParameterNode.setAttribute("name", inputValue
tim@171:                                     .getName());
tim@171:                             inputParameterNode.setAttribute("type", inputValue
tim@171:                                     .getType());
tim@171:                             inputParameterNode.setAttribute("value", inputValue
tim@171:                                     .getDefaultValue());
tim@91:                         }
tim@91:                     }
tim@64:                 }
tim@171:             } else {
tim@64:                 log.warn("No Outputmodes given.");
tim@64:             }
tim@64:         }
tim@54:         parent.appendChild(outputsNode);
tim@54:     }
tim@54: 
tim@171:     protected Collection<InputData> parseInputData(Document document,
tim@171:                                                    String xPath) {
tim@57:         log.debug("GNVArtifactBase.parseInputData");
tim@171:         HashMap<String, InputData> returnValue = null;
tim@171: 
tim@71:         log.debug(new ArtifactXMLUtilities().writeDocument2String(document));
tim@171: 
tim@171:         NodeList inputElemets = (NodeList) XMLUtils.xpath(document, xPath,
tim@171:                 XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE);// Config.getNodeSetXPath(document,
tim@171:                                                                            // "");
tim@171:         if (inputElemets != null) {
tim@171:             returnValue = new HashMap<String, InputData>(inputElemets
tim@171:                     .getLength());
tim@171:             for (int i = 0; i < inputElemets.getLength(); i++) {
tim@204:                 Element inputDataNode = (Element)inputElemets.item(i);
tim@204:                 String name = inputDataNode.getAttribute("name");
tim@204:                 String value = inputDataNode.getAttribute("value");
tim@171: 
tim@171:                 if (returnValue.containsKey(name)) {
tim@78:                     InputData inputData = returnValue.get(name);
tim@78:                     inputData.concartValue(value);
tim@78:                     log.debug(inputData.toString());
tim@78:                     returnValue.put(name, inputData);
tim@171:                 } else {
tim@171:                     InputData inputData = new DefaultInputData(name, value);
tim@171: 
tim@171:                     returnValue.put(name, inputData);
tim@78:                 }
tim@57:             }
tim@57:         }
tim@78:         return returnValue.values();
tim@57:     }
tim@99: 
tim@73:     /**
tim@117:      * @see de.intevation.artifactdatabase.DefaultArtifact#out(org.w3c.dom.Document,
tim@117:      *      java.io.OutputStream, de.intevation.artifacts.CallContext)
tim@73:      */
tim@73:     @Override
tim@117:     public void out(Document format, OutputStream outputStream,
tim@117:                     CallContext context) throws IOException {
tim@68:         log.debug("TGNVArtifactBase.out");
tim@68:         try {
tim@117: 
tim@117:             if (current != null && current instanceof OutputTransition) {
tim@117:                 ((OutputTransition) current)
ingo@299:                         .out(format, this.parseInputData(
tim@117:                                 format, "/action/out/params/input"),
tim@208:                                 outputStream, super.identifier, context.getMeta());
tim@68:             }
tim@68:         } catch (TransitionException e) {
tim@117:             log.error(e, e);
tim@89:             throw new IOException(e.getMessage());
tim@68:         }
tim@68:     }
tim@73: 
tim@171:     protected String readOutputType(Document document) {
tim@171:         String value = Config.getStringXPath(document, "action/out/@name");
tim@68:         return value;
tim@68:     }
tim@52: }