changeset 122:d3b8b0b1d010

Implemented the step-forward part of the advance operation. flys-artifacts/trunk@1446 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Ingo Weinzierl <ingo.weinzierl@intevation.de>
date Thu, 10 Mar 2011 05:56:17 +0000 (2011-03-10)
parents e0ded17a4846
children ebb1cb69d847
files flys-artifacts/ChangeLog flys-artifacts/TODO flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java
diffstat 3 files changed, 150 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- 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 <ingo@intevation.de>
+
+	* 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 <ingo@intevation.de>
 
 	* src/main/java/de/intevation/flys/artifacts/WINFOArtifact.java:
--- 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
--- 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<String> 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<String, StateData>();
+        data             = new HashMap<String, StateData>();
+        previousStateIds = new Vector<String>();
     }
 
 
@@ -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<String> 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<String> 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<String, StateData> stateData = state.getData();
+        Set<String>                 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 <i>stateId</i> 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 <i>stateId</i> 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 :

http://dive4elements.wald.intevation.org