ingo@1115: /* ingo@1115: * Copyright (c) 2010 by Intevation GmbH ingo@1115: * ingo@1115: * This program is free software under the LGPL (>=v2.1) ingo@1115: * Read the file LGPL.txt coming with the software for details ingo@1115: * or visit http://www.gnu.org/licenses/ if it does not exist. ingo@1115: */ ingo@1115: 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: * de.intevation.artifactdatabase.Artifact. sascha@803: * sascha@780: * @author Tim Englich sascha@780: * @author Ingo Weinzierl sascha@780: * @author Sascha L. Teichmann 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 states = null; sascha@778: tim@337: /** tim@337: * The Transitions which can switch between the different States. tim@337: */ tim@337: protected Collection 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 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@1062: else if((next = getPreviousState(current, targetState, context)) ingo@1062: != null) ingo@1062: { 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: // 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 name. ingo@789: */ ingo@1062: protected State getPreviousState( ingo@1062: State current, String name, CallContext context) ingo@1062: { 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@1062: current.endOfLife(context); ingo@1062: return getPreviousState(current.getParent(), name, context); ingo@470: } ingo@470: } ingo@470: ingo@470: tim@337: private boolean isStateCurrentlyReachable(String stateid){ tim@337: Iterator 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 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 target 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 = 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 data 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(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(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 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 inputValues = this.current tim@171: .getRequiredInputValues(); tim@171: if (inputValues != null) { tim@56: Iterator 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 outputModes = ((OutputState) this.current) tim@171: .getOutputModes(); tim@171: if (outputModes != null) { tim@64: Iterator 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 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 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 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 parseInputData(Document document, tim@171: String xPath) { tim@171: HashMap 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(); 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 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 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 :