Mercurial > dive4elements > gnv-client
diff gnv-artifacts/src/main/java/de/intevation/gnv/artifacts/GNVArtifactBase.java @ 657:af3f56758f59
merged gnv-artifacts/0.5
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:13:53 +0200 |
parents | 078ba6799bd2 |
children | dde7f51dbe1e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gnv-artifacts/src/main/java/de/intevation/gnv/artifacts/GNVArtifactBase.java Fri Sep 28 12:13:53 2012 +0200 @@ -0,0 +1,837 @@ +/** + * + */ +package de.intevation.gnv.artifacts; + +import de.intevation.artifactdatabase.Config; +import de.intevation.artifactdatabase.ProxyArtifact; +import de.intevation.artifactdatabase.XMLUtils; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactFactory; +import de.intevation.artifacts.ArtifactNamespaceContext; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; + +import de.intevation.gnv.artifacts.context.GNVArtifactContext; + +import de.intevation.gnv.artifacts.fis.product.Product; + +import de.intevation.gnv.artifacts.ressource.RessourceFactory; + +import de.intevation.gnv.state.DefaultInputData; +import de.intevation.gnv.state.ExportMode; +import de.intevation.gnv.state.InputData; +import de.intevation.gnv.state.InputValue; +import de.intevation.gnv.state.OutputMode; +import de.intevation.gnv.state.OutputState; +import de.intevation.gnv.state.State; +import de.intevation.gnv.state.StateFactory; + +import de.intevation.gnv.state.exception.StateException; + +import de.intevation.gnv.transition.Transition; +import de.intevation.gnv.transition.TransitionFactory; + +import de.intevation.gnv.utils.ArtifactXMLUtilities; + +import java.io.IOException; +import java.io.OutputStream; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * @author Tim Englich (tim.englich@intevation.de) + * @author Ingo Weinzierl (ingo.weinzierl@intevation.de) + * @author Sascha L. Teichmann (sascha.teichmann@intevation.de) + */ +public abstract class GNVArtifactBase extends GNVDefaultArtifact + implements PreSettingArtifact { + + /** + * the logger, used to log exceptions and additonaly information + */ + private static Logger log = Logger.getLogger(GNVArtifactBase.class); + /** + * The UID of this Class + */ + private static final long serialVersionUID = -8907096744400741458L; + + /** + * The Identifier for the Replacement of the Artifactname + */ + public static final String XPATH_IDENTIFIER_REPLACE = "IDENTIFIER"; + + /** + * The XPATH to the XML-Fragment that should be used for the Configuration + */ + public static final String XPATH_ARTIFACT_CONFIGURATION = "/artifact-database/artifacts/artifact[@name='" + + XPATH_IDENTIFIER_REPLACE + + "']"; + + public static final String XPATH_STATIC_NODE = "/art:result/art:ui/art:static"; + + public static final String XPATH_INPUT_DATA = "/art:action/art:data/art:input"; + + public static final String XPATH_INCLUDE_UI = "/art:action/art:include-ui"; + + public static final String XPATH_TARGET_NAME = "/art:action/art:target/@name"; + + public static final String XPATH_OUTPUT_NAME = "/art:action/art:out/@name"; + + public static final String XPATH_OUTPUT_PARAMS = "/art:action/art:out/art:params/art:input"; + + public static final String INITIAL_STATE = "product"; + + /** + * The current State + */ + protected State current = null; + + /** + * The States that can be used + */ + protected Map<String, State> states = null; + + /** + * The Transitions which can switch between the different States. + */ + protected Collection<Transition> transitions = null; + + /** + * The current product + */ + protected Product product; + + /** + * The Name of the Artifact + */ + protected String name = null; + + /** + * The Presettings of InputData which can be used to + * travel through the States in different Ways or + * manipulate the InputData + */ + private Map<String, InputData> preSettings = null; + + /** + * Constructor + */ + public GNVArtifactBase() { + super(); + } + + + @Override + public Document advance(Document target, CallContext context) { + log.debug("GNVArtifactBase.advance()"); + + Document result = XMLUtils.newDocument(); + String targetState = XMLUtils.xpathString( + target, XPATH_TARGET_NAME, ArtifactNamespaceContext.INSTANCE + ); + + // no current state... + if (current == null) { + log.warn("No current state. Advance not possible."); + + result = createReport( + result, + "exceptionreport", + "exception", + "No State activated." + ); + + return result; + } + + State next = null; + + try { + + // step forward + if (isStateCurrentlyReachable(targetState)) { + + next = states.get(targetState); + + // 2. Transfer Results + next.putInputData(current.getInputData(), identifier); + next.setParent(current); + next.setPreSettings(this.preSettings); + + if (current != null) { + current.endOfLife(context.globalContext()); + } + + // 3. Switch to next State + current = next; + + // 4. Initialize next Step + current.initialize(identifier, context); + + result = createReport( + result, "result", "success", "Advance success" + ); + } + + // step backward + else if((next = getPreviousState(current, targetState)) != null) { + + if (current != null) { + current.endOfLife(context.globalContext()); + } + + current = next; + + // 2. Transfer Results + current.reset(identifier); + + result = createReport( + result, "result", "success", "Advance success" + ); + } + + // goto initial step + else if(targetState.equals(INITIAL_STATE)) { + + String fis = product.getArtifactFactory(); + ArtifactDatabase db = context.getDatabase(); + GNVProductArtifactFactory fac = (GNVProductArtifactFactory) + db.getInternalArtifactFactory(fis); + + Artifact select = fac.createArtifact(identifier, context, null); + context.putContextValue(ProxyArtifact.REPLACE_PROXY, select); + + result = createReport( + result, "result", "success", "Advance success" + ); + } + + // advance not possible + else { + log.warn("advance not possible for target: " + targetState); + result = createReport( + result, + "exceptionreport", + "exception", + "Statetransition not supported" + ); + } + } + catch (StateException se) { + log.error(se, se); + result = createReport( + result, + "exceptionreport", + "exception", + se.getLocalizedMessage() + ); + } + + return result; + } + + + protected Document createReport( + Document document, + String nodeName, + String state, + String msg + ) { + XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( + document, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX + ); + + Element reportNode = creator.create(nodeName); + Element stateNode = creator.create(state); + + stateNode.setTextContent(msg); + reportNode.appendChild(stateNode); + document.appendChild(reportNode); + + return document; + + } + + + protected State getPreviousState(State current, String name) { + if (current == null) { + return null; + } + + if (current.getID().equals(name)) { + return current; + } + else { + return getPreviousState(current.getParent(), name); + } + } + + + private boolean isStateCurrentlyReachable(String stateid){ + Iterator<Transition> it = this.transitions.iterator(); + String from = this.current.getID(); + while (it.hasNext()){ + Transition transition = it.next(); + if (transition.getFrom().equals(from)){ + if (transition.getTo().equals(stateid) && transition.isValid(this.current)){ + return true; + } + } + } + return false; + } + + public Document initialize (CallContext context) { + Document result = XMLUtils.newDocument(); + try { + this.current.initialize(super.identifier, context); + result = new ArtifactXMLUtilities() + .createSuccessReport("Initialize success", + XMLUtils.newDocument()); + } catch (StateException e) { + log.error(e,e); + result = new ArtifactXMLUtilities().createExceptionReport(e + .getLocalizedMessage(), XMLUtils.newDocument()); + } + return result; + } + + protected String readStateName(Document document) { + String returnValue = XMLUtils.xpathString( + document, XPATH_TARGET_NAME, ArtifactNamespaceContext.INSTANCE); + return returnValue; + } + + protected Node getConfigurationFragment(Document document) { + log.debug("GNVArtifactBase.getConfigurationFragment"); + String xpathQuery = XPATH_ARTIFACT_CONFIGURATION.replaceAll( + XPATH_IDENTIFIER_REPLACE, this.name); + + Element configurationNode = (Element)Config.getNodeXPath(document, xpathQuery); + + String link = configurationNode.getAttribute("xlink:href"); + if (link != null ){ + String absolutFileName = Config.replaceConfigDir(link); + configurationNode = (Element)new ArtifactXMLUtilities().readConfiguration(absolutFileName); + } + + return configurationNode; + } + + /** + * @see de.intevation.artifactdatabase.DefaultArtifact#feed(org.w3c.dom.Document, + * de.intevation.artifacts.CallContext) + */ + @Override + public Document feed(Document target, CallContext context) { + log.debug("GNVArtifactBase.feed"); + Document result = XMLUtils.newDocument(); + try { + if (this.current != null) { + Collection<InputData> inputData = this.parseInputData( + target, + XPATH_INPUT_DATA); + + if (!inputData.isEmpty()){ + current.feed(inputData, super.identifier); + result = new ArtifactXMLUtilities().createSuccessReport( + "Feed success", XMLUtils.newDocument()); + }else{ + String msg = "No Inputdata given. Please select at least one Entry."; + log.warn(msg); + result = new ArtifactXMLUtilities().createExceptionReport(msg, + XMLUtils.newDocument()); + } + } else { + String msg = "No State instantiated"; + log.warn(msg); + result = new ArtifactXMLUtilities().createExceptionReport(msg, + XMLUtils.newDocument()); + } + } catch (StateException e) { + log.error(e, e); + result = new ArtifactXMLUtilities().createExceptionReport(e + .getLocalizedMessage(), XMLUtils.newDocument()); + } + return result; + } + + + /** + * @see de.intevation.artifactdatabase.DefaultArtifact#describe(org.w3c.dom.Document, de.intevation.artifacts.CallContext) + */ + @Override + public Document describe(Document data, CallContext context) { + log.debug("GNVArtifactBase.describe"); + + Document document = createDescibeOutput( + context, + identifier, + getIncludeUIFromDocument(data) + ); + + return document; + } + + /** + * @see de.intevation.artifactdatabase.DefaultArtifact#setup(java.lang.String, de.intevation.artifacts.ArtifactFactory, java.lang.Object, org.w3c.dom.Document) + */ + @Override + public void setup(String identifier, ArtifactFactory factory, + Object context,Document data) { + log.debug("GNVArtifactBase.setup"); + super.setup(identifier, factory, context, data); + + Object localContext = context; + if (context instanceof CallContext) { + localContext = ((CallContext) context).globalContext(); + + } + + if (localContext instanceof GNVArtifactContext) { + GNVArtifactContext gnvContext = (GNVArtifactContext) localContext; + Document doc = gnvContext.getConfig(); + Node artifactNode = this.getConfigurationFragment(doc); + + NodeList stateList = Config.getNodeSetXPath(artifactNode, + "states/state"); + this.states = new HashMap<String, State>(stateList + .getLength()); + for (int i = 0; i < stateList.getLength(); i++) { + State tmpState = StateFactory.getInstance() + .createState(stateList.item(i)); + if (tmpState != null) { + log.debug("Initiate new state: " + tmpState.getID()); + this.states.put(tmpState.getID(), tmpState); + if (this.current == null) { + this.current = tmpState; + } + } + } + + NodeList transitionList = Config.getNodeSetXPath(artifactNode, + "states/transition"); + this.transitions = new ArrayList<Transition>(transitionList.getLength()); + for (int i = 0; i < transitionList.getLength(); i++) { + Transition tmpTransition = TransitionFactory.getInstance() + .createTransition(transitionList.item(i)); + if (tmpTransition != null) { + this.transitions.add(tmpTransition); + } + } + + } + } + + + protected Document createDescibeOutput( + CallContext context, + String uuid, + boolean incudeUI + ) { + log.debug("GNVArtifactBase.createDescibeOutput"); + Document document = XMLUtils.newDocument(); + + XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( + document, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX + ); + Element rootNode = this.createRootNode(creator, document); + this.createHeader(creator, rootNode, document, "describe"); + this.createOutputs(creator, rootNode, document); + this.createCurrentState(creator, rootNode, document); + this.createReachableStates(creator, rootNode, document); + this.createModel(creator, rootNode, document); + if (incudeUI){ + this.createUserInterface(creator, rootNode, document, context, uuid); + } + + return document; + } + + protected boolean getIncludeUIFromDocument(Document document){ + String value = XMLUtils.xpathString( + document, XPATH_INCLUDE_UI, ArtifactNamespaceContext.INSTANCE); + + boolean includeUI = false; + if (value != null){ + includeUI = Boolean.parseBoolean(value); + } + return includeUI; + } + + protected Element createRootNode( + XMLUtils.ElementCreator creator, + Document document + ) { + Element rootNode = creator.create("result"); + document.appendChild(rootNode); + return rootNode; + } + + protected void createHeader( + XMLUtils.ElementCreator creator, + Element parent, + Document document, + String documentType + ) { + Element typeNode = creator.create("type"); + creator.addAttr(typeNode, "name", documentType); + parent.appendChild(typeNode); + + Element uuidNode = creator.create("uuid"); + creator.addAttr(uuidNode, "value", super.identifier); + parent.appendChild(uuidNode); + + Element hashNode = creator.create("hash"); + creator.addAttr(hashNode, "value", this.hash()); + parent.appendChild(hashNode); + } + + protected Element createSelectBox( + XMLUtils.ElementCreator artCreator, + XMLUtils.ElementCreator creator, + Document document, + CallContext context + ) { + RessourceFactory resource = RessourceFactory.getInstance(); + CallMeta callMeta = (CallMeta) context.getMeta(); + String productName = product.getName(); + + Element selectNode = creator.create("select1"); + creator.addAttr(selectNode, "ref", "product"); + artCreator.addAttr(selectNode, "state", INITIAL_STATE, true); + + + Element labelNode = creator.create("label"); + labelNode.setTextContent( + resource.getRessource(callMeta.getLanguages(), "product", "product") + ); + + Element choicesNode = creator.create("choices"); + + Element itemNode = creator.create("item"); + creator.addAttr(itemNode, "selected", "true"); + + Element choiceLabel = creator.create("label"); + choiceLabel.setTextContent(resource.getRessource( + callMeta.getLanguages(), + productName, + productName + )); + + Element choiceValue = creator.create("value"); + choiceValue.setTextContent(productName); + + itemNode.appendChild(choiceLabel); + itemNode.appendChild(choiceValue); + choicesNode.appendChild(itemNode); + + selectNode.appendChild(labelNode); + selectNode.appendChild(choicesNode); + + return selectNode; + } + + + protected void createReachableStates( + XMLUtils.ElementCreator creator, + Element parent, + Document document + ) { + Element stateNode = creator.create("reachable-states"); + if (this.current != null) { + + // add future states + Iterator<Transition> transitions = this.transitions.iterator(); + while (transitions.hasNext()) { + Transition tmpTransition = transitions.next(); + if (tmpTransition.getFrom().equals(current.getID()) && + tmpTransition.isValid(this.current)){ + Element currentNode = creator.create("state"); + creator.addAttr(currentNode, "name", tmpTransition.getTo()); + creator.addAttr( + currentNode, + "description", + this.states.get(tmpTransition.getTo()).getDescription()); + stateNode.appendChild(currentNode); + } + } + + + // add old states + appendOldReachableStates(creator, stateNode, current); + } + parent.appendChild(stateNode); + } + + + protected void appendOldReachableStates( + XMLUtils.ElementCreator creator, + Element parent, + State state + ) { + if (state == null) + return; + + while (state != null) { + Element currentNode = creator.create("state"); + creator.addAttr(currentNode, "name", state.getID()); + creator.addAttr(currentNode, "description", state.getDescription()); + parent.appendChild(currentNode); + + state = state.getParent(); + } + } + + + protected void createCurrentState( + XMLUtils.ElementCreator creator, + Element parent, + Document document + ) { + Element stateNode = creator.create("state"); + creator.addAttr(stateNode, "name", this.current.getID()); + creator.addAttr(stateNode, "description", this.current.getDescription()); + parent.appendChild(stateNode); + } + + protected void createModel( + XMLUtils.ElementCreator creator, + Element parent, + Document document + ) { + Element modelNode = creator.create("model"); + if (this.current != null) { + Collection<InputValue> inputValues = this.current + .getRequiredInputValues(); + if (inputValues != null) { + Iterator<InputValue> it = inputValues.iterator(); + while (it.hasNext()) { + InputValue inputValue = it.next(); + Element inputNode = creator.create("input"); + creator.addAttr(inputNode, "name", inputValue.getName()); + creator.addAttr(inputNode, "type", inputValue.getType()); + modelNode.appendChild(inputNode); + } + } + } + parent.appendChild(modelNode); + } + + protected void createUserInterface( + XMLUtils.ElementCreator creator, + Element parent, + Document document, + CallContext context, + String uuid + ) { + XMLUtils.ElementCreator xCreator = new XMLUtils.ElementCreator( + document, + XMLUtils.XFORM_URL, + XMLUtils.XFORM_PREFIX + ); + + Element uiNode = creator.create("ui"); + Element staticNode = creator.create("static"); + Element dynamic = creator.create("dynamic"); + + uiNode.appendChild(staticNode); + uiNode.appendChild(dynamic); + + parent.appendChild(uiNode); + + // append fis to dynamic part + appendFis(document, staticNode, context, product.getArtifactFactory()); + + if (this.current != null) { + Element staticUI = createSelectBox( + creator, xCreator, document, context + ); + staticNode.appendChild(staticUI); + + this.current.describe( + document, uiNode, context, uuid + ); + } + } + + + protected void createOutputs( + XMLUtils.ElementCreator creator, + Element parent, + Document document + ) { + log.debug("GNVArtifactBase.createOutputs"); + Element outputsNode = creator.create("outputs"); + if (this.current instanceof OutputState) { + Collection<OutputMode> outputModes = ((OutputState) this.current) + .getOutputModes(); + if (outputModes != null) { + Iterator<OutputMode> it = outputModes.iterator(); + while (it.hasNext()) { + OutputMode outputMode = it.next(); + log.debug("Write Outputnode for " + outputMode.toString()); + Element outputModeNode = creator.create("output"); + creator.addAttr( + outputModeNode, "name", outputMode.getName()); + creator.addAttr( + outputModeNode, "description", outputMode.getDescription()); + creator.addAttr( + outputModeNode, "mime-type", outputMode.getMimeType()); + outputsNode.appendChild(outputModeNode); + + Collection<InputValue> inputParameters = outputMode + .getInputParameters(); + if (inputParameters != null) { + Element inputParametersNode = creator.create("parameter"); + outputModeNode.appendChild(inputParametersNode); + Iterator<InputValue> it2 = inputParameters.iterator(); + while (it2.hasNext()) { + InputValue inputValue = it2.next(); + Element inputParameterNode = + creator.create("parameter"); + creator.addAttr( + inputParameterNode, "name", inputValue.getName()); + creator.addAttr( + inputParameterNode, "type", inputValue.getType()); + creator.addAttr( + inputParameterNode, "value", inputValue.getDefaultValue()); + inputParametersNode.appendChild(inputParameterNode); + } + } + + // append export modes + List<ExportMode> exportModes = outputMode.getExportModes(); + if (exportModes != null) { + Element exports = creator.create("exports"); + outputModeNode.appendChild(exports); + + for (ExportMode exp: exportModes) { + Element export = creator.create("export"); + creator.addAttr( + export, "name", exp.getName()); + creator.addAttr( + export, "description", exp.getDescription()); + creator.addAttr( + export, "mime-type", exp.getMimeType()); + + exports.appendChild(export); + } + } + } + } else { + log.warn("No Outputmodes given."); + } + } + parent.appendChild(outputsNode); + } + + protected Collection<InputData> parseInputData(Document document, + String xPath) { + HashMap<String, InputData> returnValue = null; + + NodeList inputElemets = (NodeList) XMLUtils.xpath(document, xPath, + XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE); + if (inputElemets != null) { + returnValue = new HashMap<String, InputData>(); + + for (int i = 0; i < inputElemets.getLength(); i++) { + Element inputDataNode = (Element)inputElemets.item(i); + String name = inputDataNode.getAttribute("name"); + String value = inputDataNode.getAttribute("value"); + + if (returnValue.containsKey(name)) { + InputData inputData = returnValue.get(name); + inputData.concartValue(value); + log.debug(inputData.toString()); + returnValue.put(name, inputData); + } else { + InputData inputData = new DefaultInputData(name, value); + + returnValue.put(name, inputData); + } + } + } + return returnValue.values(); + } + + /** + * @see de.intevation.artifactdatabase.DefaultArtifact#out(org.w3c.dom.Document, + * java.io.OutputStream, de.intevation.artifacts.CallContext) + */ + @Override + public void out(Document format, OutputStream outputStream, + CallContext context) throws IOException { + log.debug("TGNVArtifactBase.out"); + try { + + if (current != null && current instanceof OutputState) { + ((OutputState) current) + .out(format, this.parseInputData( + format, XPATH_OUTPUT_PARAMS), + outputStream, super.identifier, context); + } + } catch (StateException e) { + log.error(e, e); + throw new IOException(e.getMessage()); + } + } + + protected static String readOutputType(Document document) { + String value = XMLUtils.xpathString( + document, XPATH_OUTPUT_NAME, ArtifactNamespaceContext.INSTANCE); + return value; + } + + + public void setProduct(Product product) { + this.product = product; + } + + public void endOfLife(Object globalContext) { + super.endOfLife(globalContext); + + if (current != null) { + current.endOfLife(globalContext); + } + } + + /** + * @see de.intevation.gnv.artifacts.PreSettingArtifact#getPreSettings() + */ + public Map<String, InputData> getPreSettings() { + return this.preSettings; + } + + /** + * @see de.intevation.gnv.artifacts.PreSettingArtifact#setPreSettings(java.util.Map) + */ + public void setPreSettings(Map<String, InputData> preSettings) { + this.preSettings = preSettings; + if (this.current != null){ + this.current.setPreSettings(preSettings); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: