# HG changeset patch # User Ingo Weinzierl # Date 1299736577 0 # Node ID d3b8b0b1d0101338896f33a7d662517abe772d65 # Parent e0ded17a484646c2c807d2cbc4095c7805a7faa4 Implemented the step-forward part of the advance operation. flys-artifacts/trunk@1446 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r e0ded17a4846 -r d3b8b0b1d010 flys-artifacts/ChangeLog --- a/flys-artifacts/ChangeLog Wed Mar 09 14:13:57 2011 +0000 +++ b/flys-artifacts/ChangeLog Thu Mar 10 05:56:17 2011 +0000 @@ -1,3 +1,10 @@ +2011-03-10 Ingo Weinzierl + + * src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java: + Implemented a part (step forward) of the advance operation. + + * TODO: Implement Step-Back in advance operation. + 2011-03-09 Ingo Weinzierl * src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java: diff -r e0ded17a4846 -r d3b8b0b1d010 flys-artifacts/TODO --- a/flys-artifacts/TODO Wed Mar 09 14:13:57 2011 +0000 +++ b/flys-artifacts/TODO Thu Mar 10 05:56:17 2011 +0000 @@ -1,2 +1,3 @@ - Validation of the input values of an incoming feed() call - Introduction of i18n (at least error messages need this) +- Implement Step-Back diff -r e0ded17a4846 -r d3b8b0b1d010 flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java --- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java Wed Mar 09 14:13:57 2011 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java Thu Mar 10 05:56:17 2011 +0000 @@ -3,6 +3,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.Vector; import javax.xml.xpath.XPathConstants; @@ -24,6 +26,7 @@ import de.intevation.artifactdatabase.data.StateData; import de.intevation.artifactdatabase.state.State; import de.intevation.artifactdatabase.state.StateEngine; +import de.intevation.artifactdatabase.transition.TransitionEngine; import de.intevation.flys.artifacts.context.FLYSContext; @@ -43,10 +46,23 @@ public static final String XPATH_FEED_INPUT = "/art:action/art:data/art:input"; + /** The XPath that points to the name of the target state of ADVANCE.*/ + public static final String XPATH_ADVANCE_TARGET = + "/art:action/art:target/@art:name"; + + /** The constant string that shows that an operation was successful.*/ + public static final String OPERATION_SUCCESSFUL = "SUCCESS"; + + /** The constant string that shows that an operation failed.*/ + public static final String OPERATION_FAILED = "FAILURE"; + /** The identifier of the current state. */ protected String currentStateId; + /** The identifiers of previous states on a stack.*/ + protected Vector previousStateIds; + /** The name of the artifact.*/ protected String name; @@ -58,7 +74,8 @@ * The default constructor that creates an empty FLYSArtifact. */ public FLYSArtifact() { - data = new HashMap(); + data = new HashMap(); + previousStateIds = new Vector(); } @@ -139,10 +156,10 @@ try { saveData(target, XPATH_FEED_INPUT); - creator.addAttr(result, "type", "SUCCESS", true); + creator.addAttr(result, "type", OPERATION_SUCCESSFUL, true); } catch (IllegalArgumentException iae) { - creator.addAttr(result, "type", "FAILURE", true); + creator.addAttr(result, "type", OPERATION_FAILED, true); // TODO I18N this message - getMessage() returns a lookup string, no // human readable error message @@ -154,6 +171,52 @@ /** + * This method handles request for changing the current state of an + * artifact. It is possible to step forward or backward. + * + * @param target The incoming ADVANCE document. + * @param context The CallContext. + * + * @return a document that contains a SUCCESS or FAILURE message. + */ + public Document advance(Document target, CallContext context) { + Document doc = XMLUtils.newDocument(); + + XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element result = ec.create("result"); + doc.appendChild(result); + + String targetState = XMLUtils.xpathString( + target, XPATH_ADVANCE_TARGET, ArtifactNamespaceContext.INSTANCE); + + if (isStateReachable(targetState, context)) { + logger.debug("Advance: Step forward."); + + Vector prev = getPreviousStateIds(); + prev.add(getCurrentStateId()); + + setCurrentStateId(targetState); + + ec.addAttr(result, "type", OPERATION_SUCCESSFUL, true); + + return doc; + } + + // TODO IMPLEMENT STEP BACK! + + logger.warn("Advance: Cannot advance to '" + targetState + "'"); + + ec.addAttr(result, "type", OPERATION_FAILED, true); + + return doc; + } + + + /** * Returns the identifier of the current state. * * @return the identifier of the current state. @@ -201,6 +264,16 @@ /** + * Returns the vector of previous state identifiers. + * + * @return the vector of previous state identifiers. + */ + protected Vector getPreviousStateIds() { + return previousStateIds; + } + + + /** * Adds a new StateData item to the data pool of this artifact. * * @param name the name of the data object. @@ -212,6 +285,19 @@ /** + * This method returns a specific StateData object that is stored in the + * data pool of this artifact. + * + * @param name The name of the data object. + * + * @return the StateData object if existing, otherwise null. + */ + protected StateData getData(String name) { + return data.get(name); + } + + + /** * This method stores the data that is contained in the FEED document. * * @param feed The FEED document. @@ -253,5 +339,58 @@ } } } + + + /** + * This method fills a state object with the data that have been inserted to + * this artifact. This is necessary to use the isStateReachable() method, + * because the Transitions need to know about the inserted data. + * + * @param state The state that needs to be filled with data. + * + * @return the filled state. + */ + protected State fillState(State state) { + Map stateData = state.getData(); + Set keys = stateData.keySet(); + + for (String key: keys) { + StateData tmp = getData(key); + + if (tmp != null) { + StateData data = stateData.get(key); + data.setValue(tmp.getValue()); + } + } + + return state; + } + + + /** + * Determines if the state with the identifier stateId is reachable + * from the current state. The determination itself takes place in the + * TransitionEngine. + * + * @param stateId The identifier of a state. + * @param context The context object. + * + * @return true, if the state specified by stateId is reacahble, + * otherwise false. + */ + protected boolean isStateReachable(String stateId, Object context) { + logger.debug("Determine if the state '" + stateId + "' is reachable."); + + FLYSContext flysContext = getFlysContext(context); + + State currentState = fillState(getCurrentState(context)); + StateEngine sEngine = (StateEngine) flysContext.get( + FLYSContext.STATE_ENGINE_KEY); + + TransitionEngine tEngine = (TransitionEngine) flysContext.get( + FLYSContext.TRANSITION_ENGINE_KEY); + + return tEngine.isStateReachable(stateId, currentState, sEngine); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :