tim@52: package de.intevation.gnv.artifacts;
tim@52: 
sascha@779: import de.intevation.artifactdatabase.Config;
sascha@779: import de.intevation.artifactdatabase.ProxyArtifact;
sascha@779: import de.intevation.artifactdatabase.XMLUtils;
sascha@779: 
sascha@779: import de.intevation.artifacts.Artifact;
sascha@779: import de.intevation.artifacts.ArtifactDatabase;
sascha@779: import de.intevation.artifacts.ArtifactFactory;
sascha@779: import de.intevation.artifacts.ArtifactNamespaceContext;
sascha@779: import de.intevation.artifacts.CallContext;
sascha@779: import de.intevation.artifacts.CallMeta;
sascha@779: 
sascha@779: import de.intevation.gnv.artifacts.context.GNVArtifactContext;
sascha@779: 
sascha@779: import de.intevation.gnv.artifacts.fis.product.Product;
sascha@779: 
sascha@779: import de.intevation.gnv.artifacts.ressource.RessourceFactory;
sascha@779: 
sascha@779: import de.intevation.gnv.state.AutoResumeState;
sascha@779: import de.intevation.gnv.state.DefaultInputData;
sascha@779: import de.intevation.gnv.state.ExportMode;
sascha@779: import de.intevation.gnv.state.InputData;
sascha@779: import de.intevation.gnv.state.InputValue;
sascha@779: import de.intevation.gnv.state.OutputMode;
sascha@779: import de.intevation.gnv.state.OutputState;
sascha@779: import de.intevation.gnv.state.State;
sascha@779: import de.intevation.gnv.state.StateFactory;
sascha@779: 
sascha@779: import de.intevation.gnv.state.exception.StateException;
sascha@779: 
sascha@779: import de.intevation.gnv.transition.Transition;
sascha@779: import de.intevation.gnv.transition.TransitionFactory;
sascha@779: 
sascha@779: import de.intevation.gnv.utils.ArtifactXMLUtilities;
sascha@779: 
tim@73: import java.io.IOException;
tim@73: import java.io.OutputStream;
sascha@779: 
tim@337: import java.util.ArrayList;
tim@56: import java.util.Collection;
tim@52: import java.util.HashMap;
tim@54: import java.util.Iterator;
ingo@473: import java.util.List;
ingo@725: import java.util.Locale;
tim@52: import java.util.Map;
tim@52: 
tim@71: import javax.xml.xpath.XPathConstants;
tim@71: 
sascha@652: import org.apache.log4j.Logger;
sascha@779: 
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: /**
ingo@789:  * This is the major gnv artifact and handles the requests specified in
ingo@815:  * <code>de.intevation.artifactdatabase.Artifact</code>.
sascha@803:  *
sascha@780:  * @author <a href="mailto:tim.englich@intevation.de">Tim Englich</a>
sascha@780:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
sascha@780:  * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a>
tim@52:  */
sascha@778: public abstract class GNVArtifactBase extends GNVDefaultArtifact
tim@598:                                       implements PreSettingArtifact {
tim@598: 
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: 
ingo@464:     public static final String XPATH_STATIC_NODE = "/art:result/art:ui/art:static";
ingo@464: 
ingo@464:     public static final String XPATH_INPUT_DATA = "/art:action/art:data/art:input";
ingo@464: 
ingo@464:     public static final String XPATH_INCLUDE_UI = "/art:action/art:include-ui";
ingo@464: 
ingo@464:     public static final String XPATH_TARGET_NAME = "/art:action/art:target/@name";
ingo@464: 
sascha@778:     public static final String XPATH_OUTPUT_NAME = "/art:action/art:out/@name";
ingo@464: 
sascha@778:     public static final String XPATH_OUTPUT_PARAMS = "/art:action/art:out/art:params/art:input";
ingo@464: 
ingo@478:     public static final String INITIAL_STATE = "product";
ingo@470: 
tim@54:     /**
tim@335:      * The current State
tim@54:      */
tim@335:     protected State current = null;
tim@171: 
tim@54:     /**
tim@335:      * The States that can be used
tim@54:      */
tim@335:     protected Map<String, State> states = null;
sascha@778: 
tim@337:     /**
tim@337:      * The Transitions which can switch between the different States.
tim@337:      */
tim@337:     protected Collection<Transition> transitions = null;
tim@52: 
ingo@464:     /**
ingo@464:      * The current product
ingo@464:      */
ingo@464:     protected Product product;
ingo@464: 
tim@54:     /**
tim@54:      * The Name of the Artifact
tim@54:      */
tim@52:     protected String name = null;
tim@171: 
tim@52:     /**
tim@598:      * The Presettings of InputData which can be used to
tim@598:      * travel through the States in different Ways or
tim@598:      * manipulate the InputData
tim@598:      */
tim@598:     private Map<String, InputData> preSettings = null;
tim@598: 
tim@598:     /**
tim@52:      * Constructor
tim@52:      */
tim@52:     public GNVArtifactBase() {
tim@52:         super();
tim@52:     }
tim@171: 
ingo@470: 
ingo@789:     /**
ingo@789:      * This method handles request for changing the current state of an
ingo@789:      * artifact. It is possible to step forward, backward, or to the initial
ingo@789:      * state for choosing a fis.
ingo@789:      */
tim@58:     @Override
tim@73:     public Document advance(Document target, CallContext context) {
ingo@470:         log.debug("GNVArtifactBase.advance()");
ingo@470: 
ingo@470:         Document result      = XMLUtils.newDocument();
ingo@470:         String   targetState = XMLUtils.xpathString(
ingo@470:             target, XPATH_TARGET_NAME, ArtifactNamespaceContext.INSTANCE
ingo@470:         );
ingo@470: 
ingo@470:         // no current state...
ingo@470:         if (current == null) {
ingo@614:             log.warn("No current state. Advance not possible.");
ingo@470: 
ingo@470:             result = createReport(
ingo@470:                 result,
ingo@470:                 "exceptionreport",
ingo@470:                 "exception",
ingo@470:                 "No State activated."
ingo@470:             );
ingo@470: 
ingo@470:             return result;
ingo@470:         }
ingo@470: 
ingo@470:         State next = null;
ingo@470: 
tim@88:         try {
ingo@470: 
ingo@470:             // step forward
ingo@470:             if (isStateCurrentlyReachable(targetState)) {
ingo@614: 
ingo@470:                 next = states.get(targetState);
ingo@470: 
tim@735:                 boolean success = go2NextState(context, result, next);
sascha@778: 
tim@735:                 if (success){
tim@735:                     result = createReport(
tim@735:                             result, "result", "success", "Advance success"
tim@735:                         );
tim@735:                 }else{
tim@735:                     result =  ArtifactXMLUtilities.
sascha@778:                     createExceptionReport("Error while going to next State.",
tim@735:                             XMLUtils.newDocument());
sascha@481:                 }
tim@58:             }
ingo@470: 
ingo@470:             // step backward
ingo@470:             else if((next = getPreviousState(current, targetState)) != null) {
ingo@473: 
sascha@481:                 if (current != null) {
sascha@481:                     current.endOfLife(context.globalContext());
sascha@481:                 }
sascha@481: 
ingo@470:                 current = next;
ingo@470: 
ingo@614:                 // 2. Transfer Results
ingo@614:                 current.reset(identifier);
ingo@614: 
ingo@470:                 result = createReport(
ingo@470:                     result, "result", "success", "Advance success"
ingo@470:                 );
ingo@470:             }
ingo@470: 
ingo@470:             // goto initial step
ingo@470:             else if(targetState.equals(INITIAL_STATE)) {
ingo@478: 
ingo@478:                 String fis                    = product.getArtifactFactory();
ingo@478:                 ArtifactDatabase db           = context.getDatabase();
ingo@478:                 GNVProductArtifactFactory fac = (GNVProductArtifactFactory)
ingo@478:                     db.getInternalArtifactFactory(fis);
ingo@478: 
tim@594:                 Artifact select = fac.createArtifact(identifier, context, null);
ingo@470:                 context.putContextValue(ProxyArtifact.REPLACE_PROXY, select);
ingo@470: 
ingo@470:                 result = createReport(
ingo@470:                     result, "result", "success", "Advance success"
ingo@470:                 );
ingo@470:             }
ingo@470: 
ingo@470:             // advance not possible
ingo@470:             else {
ingo@470:                 log.warn("advance not possible for target: " + targetState);
ingo@470:                 result = createReport(
ingo@470:                     result,
ingo@470:                     "exceptionreport",
ingo@470:                     "exception",
ingo@470:                     "Statetransition not supported"
ingo@470:                 );
ingo@470:             }
tim@58:         }
ingo@470:         catch (StateException se) {
ingo@470:             log.error(se, se);
ingo@470:             result = createReport(
ingo@470:                 result,
ingo@470:                 "exceptionreport",
ingo@470:                 "exception",
ingo@470:                 se.getLocalizedMessage()
ingo@470:             );
ingo@470:         }
ingo@470: 
tim@58:         return result;
tim@58:     }
ingo@470: 
ingo@470: 
tim@735:     private boolean go2NextState(CallContext context, Document result,
tim@735:                                   State next) throws StateException {
tim@735:         // 2. Transfer Results
tim@735:         next.putInputData(current.getInputData(), identifier);
tim@735:         next.setParent(current);
tim@735:         next.setPreSettings(this.preSettings);
tim@735: 
tim@735:         if (current != null) {
tim@735:             current.endOfLife(context.globalContext());
tim@735:         }
tim@735: 
tim@735:         // 3. Switch to next State
tim@735:         current = next;
tim@735: 
tim@735:         // 4. Initialize next Step
tim@735:         current.initialize(identifier, context);
tim@735: 
tim@735:         return true;
tim@735:     }
tim@735: 
tim@735: 
ingo@470:     protected Document createReport(
ingo@470:         Document document,
ingo@470:         String   nodeName,
ingo@470:         String   state,
ingo@470:         String   msg
ingo@470:     ) {
ingo@470:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@470:             document,
ingo@470:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@470:             ArtifactNamespaceContext.NAMESPACE_PREFIX
ingo@470:         );
ingo@470: 
ingo@470:         Element reportNode = creator.create(nodeName);
ingo@470:         Element stateNode  = creator.create(state);
ingo@470: 
ingo@470:         stateNode.setTextContent(msg);
ingo@470:         reportNode.appendChild(stateNode);
ingo@470:         document.appendChild(reportNode);
ingo@470: 
ingo@470:         return document;
ingo@470: 
ingo@470:     }
ingo@470: 
ingo@470: 
ingo@789:     /**
ingo@789:      * Step back to the previous state specified by <code>name</code>.
ingo@789:      */
ingo@470:     protected State getPreviousState(State current, String name) {
ingo@470:         if (current == null) {
ingo@470:             return null;
ingo@470:         }
ingo@470: 
ingo@470:         if (current.getID().equals(name)) {
ingo@470:             return current;
ingo@470:         }
ingo@470:         else {
ingo@470:             return getPreviousState(current.getParent(), name);
ingo@470:         }
ingo@470:     }
ingo@470: 
ingo@470: 
tim@337:     private boolean isStateCurrentlyReachable(String stateid){
tim@337:         Iterator<Transition> it = this.transitions.iterator();
tim@337:         String from = this.current.getID();
tim@337:         while (it.hasNext()){
tim@337:             Transition transition = it.next();
tim@337:             if (transition.getFrom().equals(from)){
tim@337:                 if (transition.getTo().equals(stateid) && transition.isValid(this.current)){
tim@337:                     return true;
tim@337:                 }
tim@337:             }
tim@337:         }
tim@337:         return false;
tim@337:     }
sascha@778: 
ingo@815: 
ingo@789:     public Document initialize(CallContext context) {
tim@325:         Document result = XMLUtils.newDocument();
tim@325:         try {
ingo@493:             this.current.initialize(super.identifier, context);
sascha@778: 
tim@735:             if (this.current instanceof AutoResumeState){
tim@735:                 // Jump to next State using the Transitions.
tim@735:                 State next = this.getNextReachableState(this.current);
tim@735:                 if (next != null){
tim@735:                     boolean success = go2NextState(context, result, next);
tim@735:                     if (success){
tim@735:                         result = ArtifactXMLUtilities
tim@735:                         .createSuccessReport("Initialize success",
tim@735:                                 XMLUtils.newDocument());
tim@735:                     }else{
tim@735:                         result =  ArtifactXMLUtilities.
tim@735:                                     createExceptionReport(
sascha@778:                                             "Error while going to next State.",
tim@735:                                             XMLUtils.newDocument());
tim@735:                     }
tim@735:                 }else{
tim@735:                     result = ArtifactXMLUtilities.
sascha@778:                                      createExceptionReport("No propper State found.",
tim@735:                                                            XMLUtils.newDocument());
tim@735:                 }
tim@735:             }else{
tim@735:                 result = ArtifactXMLUtilities
tim@735:                             .createSuccessReport("Initialize success",
tim@735:                                     XMLUtils.newDocument());
tim@735:             }
tim@335:         } catch (StateException e) {
tim@325:             log.error(e,e);
tim@735:             result = ArtifactXMLUtilities.createExceptionReport(e
tim@325:                     .getLocalizedMessage(), XMLUtils.newDocument());
tim@325:         }
tim@325:         return result;
tim@325:     }
sascha@778: 
ingo@789:     /**
ingo@789:      * Step forward to the next reachable state.
ingo@789:      * @param current Current state.
ingo@789:      * @return Reachable state.
ingo@789:      */
tim@735:     protected State getNextReachableState(State current){
tim@735:         Iterator<Transition> it = this.transitions.iterator();
tim@735:         String from = current.getID();
tim@735:         while (it.hasNext()){
tim@735:             Transition transition = it.next();
tim@735:             if (transition.getFrom().equals(from)){
tim@735:                 if (transition.isValid(current)){
tim@735:                     return this.states.get(transition.getTo());
tim@735:                 }
tim@735:             }
tim@735:         }
tim@735:         return null;
tim@735:     }
tim@58: 
ingo@815: 
tim@335:     protected String readStateName(Document document) {
ingo@464:         String returnValue = XMLUtils.xpathString(
ingo@464:             document, XPATH_TARGET_NAME, ArtifactNamespaceContext.INSTANCE);
tim@58:         return returnValue;
tim@58:     }
tim@58: 
ingo@815: 
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);
sascha@778: 
tim@204:         Element configurationNode = (Element)Config.getNodeXPath(document, xpathQuery);
sascha@778: 
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:         }
sascha@778: 
tim@204:         return configurationNode;
tim@204:     }
tim@171: 
tim@52:     /**
ingo@789:      * Insert new data included in <code>target</code> into the current state.
ingo@789:      * @param target XML document which contains data.
ingo@789:      * @param context CallContext
ingo@789:      * @return XML document with success or error message.
tim@57:      */
tim@57:     @Override
tim@73:     public Document feed(Document target, CallContext context) {
tim@89:         log.debug("GNVArtifactBase.feed");
ingo@725:         RessourceFactory fac = RessourceFactory.getInstance();
ingo@725:         Locale[] locales     = fac.getLocales();
ingo@725:         Locale   locale      = context.getMeta().getPreferredLocale(locales);
ingo@725:         Document result      = XMLUtils.newDocument();
ingo@725: 
tim@57:         try {
tim@171:             if (this.current != null) {
ingo@464:                 Collection<InputData> inputData = this.parseInputData(
ingo@464:                     target,
ingo@464:                     XPATH_INPUT_DATA);
ingo@464: 
tim@194:                 if (!inputData.isEmpty()){
ingo@725:                     result = current.feed(context, inputData, super.identifier);
tim@194:                 }else{
ingo@725:                     //String msg = "No Inputdata given. Please select at least one Entry.";
ingo@725:                     String msg = fac.getRessource(
ingo@725:                         locale,
ingo@725:                         EXCEPTION_NO_INPUT,
ingo@725:                         EXCEPTION_NO_INPUT);
ingo@725: 
tim@194:                     log.warn(msg);
tim@735:                     result = ArtifactXMLUtilities.createInputExceptionReport(
ingo@725:                         msg,
ingo@725:                         XMLUtils.newDocument());
tim@194:                 }
tim@171:             } else {
tim@335:                 String msg = "No State instantiated";
tim@89:                 log.warn(msg);
tim@735:                 result = ArtifactXMLUtilities.createExceptionReport(msg,
tim@171:                         XMLUtils.newDocument());
tim@57:             }
tim@335:         } catch (StateException e) {
tim@171:             log.error(e, e);
tim@735:             result = ArtifactXMLUtilities.createExceptionReport(e
tim@171:                     .getLocalizedMessage(), XMLUtils.newDocument());
tim@57:         }
tim@57:         return result;
tim@57:     }
tim@171: 
ingo@464: 
ingo@464:     /**
ingo@789:      * Describe the current artifact.
ingo@789:      * @return The description of the current artifact.
ingo@464:      */
ingo@464:     @Override
ingo@464:     public Document describe(Document data, CallContext context) {
ingo@464:         log.debug("GNVArtifactBase.describe");
ingo@464: 
ingo@464:         Document document = createDescibeOutput(
ingo@488:             context,
ingo@464:             identifier,
ingo@464:             getIncludeUIFromDocument(data)
ingo@464:         );
ingo@464: 
ingo@464:         return document;
ingo@464:     }
ingo@464: 
tim@57:     /**
ingo@789:      * Initialse this artifact and insert some data if <code>data</code>
ingo@789:      * contains necessary information for this artifact.
tim@52:      */
tim@52:     @Override
sascha@778:     public void setup(String identifier, ArtifactFactory factory,
tim@594:                       Object context,Document data) {
tim@52:         log.debug("GNVArtifactBase.setup");
tim@594:         super.setup(identifier, factory, context, data);
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);
sascha@778: 
tim@335:             NodeList stateList = Config.getNodeSetXPath(artifactNode,
tim@335:                     "states/state");
tim@335:             this.states = new HashMap<String, State>(stateList
tim@171:                     .getLength());
tim@335:             for (int i = 0; i < stateList.getLength(); i++) {
tim@335:                 State tmpState = StateFactory.getInstance()
tim@335:                         .createState(stateList.item(i));
tim@335:                 if (tmpState != null) {
ingo@470:                     log.debug("Initiate new state: " + tmpState.getID());
tim@335:                     this.states.put(tmpState.getID(), tmpState);
tim@171:                     if (this.current == null) {
tim@335:                         this.current = tmpState;
tim@52:                     }
tim@52:                 }
tim@52:             }
sascha@778: 
tim@337:             NodeList transitionList = Config.getNodeSetXPath(artifactNode,
tim@337:             "states/transition");
tim@337:             this.transitions = new ArrayList<Transition>(transitionList.getLength());
tim@337:             for (int i = 0; i < transitionList.getLength(); i++) {
tim@337:                 Transition tmpTransition = TransitionFactory.getInstance()
tim@337:                         .createTransition(transitionList.item(i));
tim@337:                 if (tmpTransition != null) {
tim@337:                     this.transitions.add(tmpTransition);
tim@337:                 }
tim@337:             }
tim@171: 
tim@52:         }
tim@52:     }
tim@171: 
ingo@488: 
ingo@789:     /**
ingo@789:      * Create the xml document returned in {@link #describe(org.w3c.dom.Document,
ingo@789:      * de.intevation.artifacts.CallContext)}
ingo@789:      */
ingo@488:     protected Document createDescibeOutput(
ingo@488:         CallContext context,
ingo@488:         String      uuid,
ingo@488:         boolean     incudeUI
ingo@488:     ) {
tim@54:         log.debug("GNVArtifactBase.createDescibeOutput");
tim@71:         Document document = XMLUtils.newDocument();
ingo@488: 
ingo@464:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@464:             document,
ingo@464:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@464:             ArtifactNamespaceContext.NAMESPACE_PREFIX
ingo@464:         );
ingo@470:         Element rootNode = this.createRootNode(creator, document);
ingo@464:         this.createHeader(creator, rootNode, document, "describe");
ingo@464:         this.createOutputs(creator, rootNode, document);
ingo@464:         this.createCurrentState(creator, rootNode, document);
ingo@464:         this.createReachableStates(creator, rootNode, document);
ingo@464:         this.createModel(creator, rootNode, document);
tim@222:         if (incudeUI){
ingo@488:             this.createUserInterface(creator, rootNode, document, context, uuid);
tim@222:         }
ingo@464: 
tim@54:         return document;
tim@54:     }
sascha@778: 
ingo@789:     /**
ingo@789:      * Determine the wish to append the user interface description to the
ingo@789:      * describe document.
sascha@803:      *
ingo@789:      * @return True, if the user interface description should be appended,
ingo@789:      * otherwise false.
ingo@789:      */
tim@222:     protected boolean getIncludeUIFromDocument(Document document){
ingo@464:         String value = XMLUtils.xpathString(
ingo@464:             document, XPATH_INCLUDE_UI, ArtifactNamespaceContext.INSTANCE);
ingo@464: 
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: 
ingo@815: 
ingo@470:     protected Element createRootNode(
ingo@470:         XMLUtils.ElementCreator creator,
ingo@470:         Document                document
ingo@470:     ) {
ingo@470:         Element rootNode = creator.create("result");
tim@54:         document.appendChild(rootNode);
tim@54:         return rootNode;
tim@54:     }
tim@171: 
ingo@789:     /**
ingo@789:      * Append information about the current artifact (uuid, hash).
ingo@789:      */
ingo@464:     protected void createHeader(
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Element                 parent,
ingo@464:         Document                document,
ingo@464:         String                  documentType
ingo@478:     ) {
ingo@464:         Element typeNode = creator.create("type");
ingo@464:         creator.addAttr(typeNode, "name", documentType);
tim@54:         parent.appendChild(typeNode);
tim@171: 
ingo@464:         Element uuidNode = creator.create("uuid");
ingo@464:         creator.addAttr(uuidNode, "value", super.identifier);
tim@54:         parent.appendChild(uuidNode);
tim@171: 
ingo@464:         Element hashNode = creator.create("hash");
ingo@464:         creator.addAttr(hashNode, "value", this.hash());
tim@54:         parent.appendChild(hashNode);
tim@89:     }
tim@54: 
ingo@789:     /**
ingo@789:      * Create the fis select box.
ingo@789:      */
ingo@464:     protected Element createSelectBox(
ingo@478:         XMLUtils.ElementCreator artCreator,
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Document                document,
ingo@464:         CallContext             context
ingo@464:     ) {
ingo@464:         RessourceFactory resource = RessourceFactory.getInstance();
ingo@464:         CallMeta callMeta         = (CallMeta) context.getMeta();
ingo@478:         String productName        = product.getName();
ingo@464: 
ingo@464:         Element selectNode = creator.create("select1");
ingo@464:         creator.addAttr(selectNode, "ref", "product");
ingo@478:         artCreator.addAttr(selectNode, "state", INITIAL_STATE, true);
ingo@478: 
ingo@464: 
ingo@464:         Element labelNode = creator.create("label");
ingo@464:         labelNode.setTextContent(
ingo@464:             resource.getRessource(callMeta.getLanguages(), "product", "product")
ingo@464:         );
ingo@464: 
ingo@464:         Element choicesNode = creator.create("choices");
ingo@464: 
ingo@464:         Element itemNode = creator.create("item");
ingo@464:         creator.addAttr(itemNode, "selected", "true");
ingo@464: 
ingo@464:         Element choiceLabel = creator.create("label");
ingo@464:         choiceLabel.setTextContent(resource.getRessource(
ingo@464:             callMeta.getLanguages(),
ingo@464:             productName,
ingo@464:             productName
ingo@464:         ));
ingo@464: 
ingo@464:         Element choiceValue = creator.create("value");
ingo@464:         choiceValue.setTextContent(productName);
ingo@464: 
ingo@464:         itemNode.appendChild(choiceLabel);
ingo@464:         itemNode.appendChild(choiceValue);
ingo@464:         choicesNode.appendChild(itemNode);
ingo@464: 
ingo@464:         selectNode.appendChild(labelNode);
ingo@464:         selectNode.appendChild(choicesNode);
ingo@464: 
ingo@464:         return selectNode;
ingo@464:     }
ingo@464: 
ingo@488: 
ingo@789:     /**
ingo@789:      * Insert all reachable states into the describe document returned by
ingo@789:      * {@link #describe(org.w3c.dom.Document, de.intevation.artifacts.CallContext)}
ingo@789:      */
ingo@464:     protected void createReachableStates(
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Element                 parent,
ingo@464:         Document                document
ingo@464:     ) {
ingo@464:         Element stateNode = creator.create("reachable-states");
tim@171:         if (this.current != null) {
ingo@473: 
ingo@473:             // add future states
tim@337:             Iterator<Transition> transitions = this.transitions.iterator();
tim@337:             while (transitions.hasNext()) {
tim@337:                 Transition tmpTransition = transitions.next();
ingo@614:                 if (tmpTransition.getFrom().equals(current.getID()) &&
tim@337:                     tmpTransition.isValid(this.current)){
ingo@464:                     Element currentNode = creator.create("state");
ingo@464:                     creator.addAttr(currentNode, "name", tmpTransition.getTo());
ingo@464:                     creator.addAttr(
ingo@464:                         currentNode,
ingo@464:                         "description",
ingo@464:                         this.states.get(tmpTransition.getTo()).getDescription());
tim@337:                     stateNode.appendChild(currentNode);
tim@337:                 }
tim@54:             }
ingo@473: 
ingo@473: 
ingo@473:             // add old states
ingo@473:             appendOldReachableStates(creator, stateNode, current);
tim@54:         }
tim@54:         parent.appendChild(stateNode);
tim@54:     }
tim@171: 
ingo@473: 
ingo@789:     /**
ingo@789:      * Insert states which have been visited by this artifact into the xml
ingo@789:      * document returned by {@link #describe(org.w3c.dom.Document,
ingo@789:      * de.intevation.artifacts.CallContext)}
ingo@789:      */
ingo@473:     protected void appendOldReachableStates(
ingo@473:         XMLUtils.ElementCreator creator,
ingo@473:         Element                 parent,
ingo@473:         State                   state
ingo@473:     ) {
ingo@473:         if (state == null)
ingo@473:             return;
ingo@473: 
ingo@473:         while (state != null) {
ingo@473:             Element currentNode = creator.create("state");
ingo@473:             creator.addAttr(currentNode, "name", state.getID());
ingo@473:             creator.addAttr(currentNode, "description", state.getDescription());
ingo@473:             parent.appendChild(currentNode);
ingo@473: 
ingo@473:             state = state.getParent();
ingo@473:         }
ingo@473:     }
ingo@473: 
ingo@473: 
ingo@789:     /**
ingo@789:      * Insert the current state into the xml document returned by
ingo@789:      * {@link #describe(org.w3c.dom.Document, de.intevation.artifacts.CallContext)}
ingo@789:      */
ingo@464:     protected void createCurrentState(
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Element                 parent,
ingo@464:         Document                document
ingo@464:     ) {
ingo@464:         Element stateNode = creator.create("state");
ingo@464:         creator.addAttr(stateNode, "name", this.current.getID());
ingo@464:         creator.addAttr(stateNode, "description", this.current.getDescription());
tim@54:         parent.appendChild(stateNode);
tim@54:     }
tim@171: 
ingo@815: 
ingo@464:     protected void createModel(
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Element                 parent,
ingo@464:         Document                document
ingo@464:     ) {
ingo@464:         Element modelNode = creator.create("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();
ingo@464:                     Element inputNode = creator.create("input");
ingo@464:                     creator.addAttr(inputNode, "name", inputValue.getName());
ingo@464:                     creator.addAttr(inputNode, "type", inputValue.getType());
tim@56:                     modelNode.appendChild(inputNode);
tim@56:                 }
tim@56:             }
tim@56:         }
tim@54:         parent.appendChild(modelNode);
tim@54:     }
tim@171: 
ingo@789:     /**
ingo@789:      * Append the user interface description to the document returned by
ingo@789:      * {@link #describe(org.w3c.dom.Document, de.intevation.artifacts.CallContext)}
ingo@789:      * @param creator XML element creator.
ingo@789:      * @param parent New elements are appended to this node.
ingo@789:      * @param document Current document.
ingo@789:      * @param context CallContext
ingo@789:      * @param uuid The uuid of the artifact.
ingo@789:      */
ingo@464:     protected void createUserInterface(
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Element                 parent,
ingo@464:         Document                document,
ingo@488:         CallContext             context,
ingo@488:         String                  uuid
ingo@464:     ) {
ingo@488:         XMLUtils.ElementCreator xCreator = new XMLUtils.ElementCreator(
ingo@488:             document,
ingo@488:             XMLUtils.XFORM_URL,
ingo@488:             XMLUtils.XFORM_PREFIX
ingo@488:         );
ingo@488: 
ingo@488:         Element uiNode     = creator.create("ui");
ingo@488:         Element staticNode = creator.create("static");
ingo@488:         Element dynamic    = creator.create("dynamic");
ingo@488: 
ingo@488:         uiNode.appendChild(staticNode);
ingo@488:         uiNode.appendChild(dynamic);
ingo@488: 
ingo@488:         parent.appendChild(uiNode);
ingo@488: 
ingo@488:         // append fis to dynamic part
ingo@488:         appendFis(document, staticNode, context, product.getArtifactFactory());
tim@171: 
tim@171:         if (this.current != null) {
ingo@488:             Element staticUI = createSelectBox(
ingo@488:                 creator, xCreator, document, context
ingo@488:             );
ingo@488:             staticNode.appendChild(staticUI);
ingo@488: 
ingo@478:             this.current.describe(
ingo@493:                 document, uiNode, context, uuid
ingo@478:             );
tim@61:         }
tim@54:     }
tim@171: 
ingo@478: 
ingo@789:     /**
ingo@789:      * Append possible output targets to the document returned by
ingo@789:      * {@link #describe(org.w3c.dom.Document, de.intevation.artifacts.CallContext)}
ingo@789:      * @param creator Used to create xml elements.
ingo@789:      * @param parent New elements are appended to this node.
ingo@789:      * @param document The current document.
ingo@789:      */
ingo@464:     protected void createOutputs(
ingo@464:         XMLUtils.ElementCreator creator,
ingo@464:         Element                 parent,
ingo@464:         Document                document
ingo@464:     ) {
tim@64:         log.debug("GNVArtifactBase.createOutputs");
ingo@464:         Element outputsNode = creator.create("outputs");
tim@335:         if (this.current instanceof OutputState) {
tim@335:             Collection<OutputMode> outputModes = ((OutputState) 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());
ingo@464:                     Element outputModeNode = creator.create("output");
ingo@464:                     creator.addAttr(
ingo@464:                         outputModeNode, "name", outputMode.getName());
ingo@464:                     creator.addAttr(
ingo@464:                         outputModeNode, "description", outputMode.getDescription());
ingo@464:                     creator.addAttr(
ingo@464:                         outputModeNode, "mime-type", outputMode.getMimeType());
tim@64:                     outputsNode.appendChild(outputModeNode);
tim@171: 
tim@171:                     Collection<InputValue> inputParameters = outputMode
tim@171:                             .getInputParameters();
tim@171:                     if (inputParameters != null) {
ingo@464:                         Element inputParametersNode = creator.create("parameter");
tim@91:                         outputModeNode.appendChild(inputParametersNode);
tim@91:                         Iterator<InputValue> it2 = inputParameters.iterator();
tim@171:                         while (it2.hasNext()) {
tim@91:                             InputValue inputValue = it2.next();
ingo@464:                             Element inputParameterNode =
ingo@464:                                 creator.create("parameter");
ingo@464:                             creator.addAttr(
ingo@464:                                 inputParameterNode, "name", inputValue.getName());
ingo@464:                             creator.addAttr(
ingo@464:                                 inputParameterNode, "type", inputValue.getType());
ingo@464:                             creator.addAttr(
ingo@464:                                 inputParameterNode, "value", inputValue.getDefaultValue());
tim@91:                             inputParametersNode.appendChild(inputParameterNode);
tim@91:                         }
tim@91:                     }
ingo@626: 
ingo@626:                     // append export modes
ingo@626:                     List<ExportMode> exportModes = outputMode.getExportModes();
ingo@626:                     if (exportModes != null) {
ingo@626:                         Element exports = creator.create("exports");
ingo@626:                         outputModeNode.appendChild(exports);
ingo@626: 
ingo@626:                         for (ExportMode exp: exportModes) {
ingo@626:                             Element export = creator.create("export");
ingo@626:                             creator.addAttr(
ingo@626:                                 export, "name", exp.getName());
ingo@626:                             creator.addAttr(
ingo@626:                                 export, "description", exp.getDescription());
ingo@626:                             creator.addAttr(
ingo@626:                                 export, "mime-type", exp.getMimeType());
ingo@626: 
ingo@626:                             exports.appendChild(export);
ingo@626:                         }
ingo@626:                     }
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: 
ingo@789:     /**
ingo@789:      * Parse input data from feed-document.
ingo@789:      * @param document Feed-document
ingo@789:      * @param xPath Path to input data.
ingo@789:      * @return A collection with InputData objects.
ingo@789:      */
tim@171:     protected Collection<InputData> parseInputData(Document document,
tim@171:                                                    String xPath) {
tim@171:         HashMap<String, InputData> returnValue = null;
tim@171: 
tim@171:         NodeList inputElemets = (NodeList) XMLUtils.xpath(document, xPath,
ingo@464:                 XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE);
tim@171:         if (inputElemets != null) {
ingo@464:             returnValue = new HashMap<String, InputData>();
ingo@464: 
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:     /**
ingo@789:      * Call an output target (e.g. chart, wms, etc.)
ingo@789:      * @param format XML document which contains some further information about
ingo@789:      * the desired output.
ingo@789:      * @param outputStream Stream used for writing the output.
ingo@789:      * @param context CallContext
ingo@789:      * @throws IOException If an error occured while writing the result to the
ingo@789:      * output stream.
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@335:             if (current != null && current instanceof OutputState) {
tim@335:                 ((OutputState) current)
ingo@299:                         .out(format, this.parseInputData(
ingo@464:                                 format, XPATH_OUTPUT_PARAMS),
ingo@358:                                 outputStream, super.identifier, context);
tim@68:             }
tim@335:         } catch (StateException e) {
tim@117:             log.error(e, e);
tim@89:             throw new IOException(e.getMessage());
tim@68:         }
tim@68:     }
tim@73: 
ingo@815: 
sascha@481:     protected static String readOutputType(Document document) {
ingo@464:         String value = XMLUtils.xpathString(
ingo@464:             document, XPATH_OUTPUT_NAME, ArtifactNamespaceContext.INSTANCE);
tim@68:         return value;
tim@68:     }
ingo@464: 
ingo@464: 
ingo@789:     /**
ingo@789:      * The the current product.
ingo@789:      * @param product New product.
ingo@789:      */
ingo@464:     public void setProduct(Product product) {
tim@598:         this.product = product;
ingo@464:     }
sascha@481: 
ingo@789:     /**
ingo@789:      * Call endOfLife of parent class and the current state.
ingo@789:      */
ingo@789:     @Override
sascha@481:     public void endOfLife(Object globalContext) {
sascha@481:         super.endOfLife(globalContext);
sascha@481: 
sascha@481:         if (current != null) {
sascha@481:             current.endOfLife(globalContext);
sascha@481:         }
sascha@481:     }
sascha@778: 
tim@598:     /**
ingo@789:      * Retrieves a map with given InputData which have been inserted into the
ingo@789:      * current artifact before the parameterization began.
tim@598:      */
tim@598:     public Map<String, InputData> getPreSettings() {
tim@598:         return this.preSettings;
tim@598:     }
sascha@778: 
tim@598:     /**
ingo@789:      * Set InputData which are used in later states.
tim@598:      */
tim@598:     public void setPreSettings(Map<String, InputData> preSettings) {
tim@598:         this.preSettings = preSettings;
tim@598:         if (this.current != null){
tim@598:             this.current.setPreSettings(preSettings);
tim@598:         }
tim@598:     }
tim@52: }
ingo@789: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :