comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/FLYSArtifact.java @ 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
parents e0ded17a4846
children ebb1cb69d847
comparison
equal deleted inserted replaced
121:e0ded17a4846 122:d3b8b0b1d010
1 package de.intevation.flys.artifacts; 1 package de.intevation.flys.artifacts;
2 2
3 import java.util.HashMap; 3 import java.util.HashMap;
4 import java.util.List; 4 import java.util.List;
5 import java.util.Map; 5 import java.util.Map;
6 import java.util.Set;
7 import java.util.Vector;
6 8
7 import javax.xml.xpath.XPathConstants; 9 import javax.xml.xpath.XPathConstants;
8 10
9 import org.apache.log4j.Logger; 11 import org.apache.log4j.Logger;
10 12
22 import de.intevation.artifactdatabase.DefaultArtifact; 24 import de.intevation.artifactdatabase.DefaultArtifact;
23 import de.intevation.artifactdatabase.data.DefaultStateData; 25 import de.intevation.artifactdatabase.data.DefaultStateData;
24 import de.intevation.artifactdatabase.data.StateData; 26 import de.intevation.artifactdatabase.data.StateData;
25 import de.intevation.artifactdatabase.state.State; 27 import de.intevation.artifactdatabase.state.State;
26 import de.intevation.artifactdatabase.state.StateEngine; 28 import de.intevation.artifactdatabase.state.StateEngine;
29 import de.intevation.artifactdatabase.transition.TransitionEngine;
27 30
28 import de.intevation.flys.artifacts.context.FLYSContext; 31 import de.intevation.flys.artifacts.context.FLYSContext;
29 32
30 33
31 /** 34 /**
41 44
42 /** The XPath that points to the input data elements of the FEED document.*/ 45 /** The XPath that points to the input data elements of the FEED document.*/
43 public static final String XPATH_FEED_INPUT = 46 public static final String XPATH_FEED_INPUT =
44 "/art:action/art:data/art:input"; 47 "/art:action/art:data/art:input";
45 48
49 /** The XPath that points to the name of the target state of ADVANCE.*/
50 public static final String XPATH_ADVANCE_TARGET =
51 "/art:action/art:target/@art:name";
52
53 /** The constant string that shows that an operation was successful.*/
54 public static final String OPERATION_SUCCESSFUL = "SUCCESS";
55
56 /** The constant string that shows that an operation failed.*/
57 public static final String OPERATION_FAILED = "FAILURE";
58
46 59
47 /** The identifier of the current state. */ 60 /** The identifier of the current state. */
48 protected String currentStateId; 61 protected String currentStateId;
49 62
63 /** The identifiers of previous states on a stack.*/
64 protected Vector<String> previousStateIds;
65
50 /** The name of the artifact.*/ 66 /** The name of the artifact.*/
51 protected String name; 67 protected String name;
52 68
53 /** The data that have been inserted into this artifact.*/ 69 /** The data that have been inserted into this artifact.*/
54 protected Map<String, StateData> data; 70 protected Map<String, StateData> data;
56 72
57 /** 73 /**
58 * The default constructor that creates an empty FLYSArtifact. 74 * The default constructor that creates an empty FLYSArtifact.
59 */ 75 */
60 public FLYSArtifact() { 76 public FLYSArtifact() {
61 data = new HashMap<String, StateData>(); 77 data = new HashMap<String, StateData>();
78 previousStateIds = new Vector<String>();
62 } 79 }
63 80
64 81
65 /** 82 /**
66 * Returns the name of the concrete artifact. 83 * Returns the name of the concrete artifact.
137 Element result = creator.create("result"); 154 Element result = creator.create("result");
138 doc.appendChild(result); 155 doc.appendChild(result);
139 156
140 try { 157 try {
141 saveData(target, XPATH_FEED_INPUT); 158 saveData(target, XPATH_FEED_INPUT);
142 creator.addAttr(result, "type", "SUCCESS", true); 159 creator.addAttr(result, "type", OPERATION_SUCCESSFUL, true);
143 } 160 }
144 catch (IllegalArgumentException iae) { 161 catch (IllegalArgumentException iae) {
145 creator.addAttr(result, "type", "FAILURE", true); 162 creator.addAttr(result, "type", OPERATION_FAILED, true);
146 163
147 // TODO I18N this message - getMessage() returns a lookup string, no 164 // TODO I18N this message - getMessage() returns a lookup string, no
148 // human readable error message 165 // human readable error message
149 result.setTextContent(iae.getMessage()); 166 result.setTextContent(iae.getMessage());
150 } 167 }
168
169 return doc;
170 }
171
172
173 /**
174 * This method handles request for changing the current state of an
175 * artifact. It is possible to step forward or backward.
176 *
177 * @param target The incoming ADVANCE document.
178 * @param context The CallContext.
179 *
180 * @return a document that contains a SUCCESS or FAILURE message.
181 */
182 public Document advance(Document target, CallContext context) {
183 Document doc = XMLUtils.newDocument();
184
185 XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator(
186 doc,
187 ArtifactNamespaceContext.NAMESPACE_URI,
188 ArtifactNamespaceContext.NAMESPACE_PREFIX);
189
190 Element result = ec.create("result");
191 doc.appendChild(result);
192
193 String targetState = XMLUtils.xpathString(
194 target, XPATH_ADVANCE_TARGET, ArtifactNamespaceContext.INSTANCE);
195
196 if (isStateReachable(targetState, context)) {
197 logger.debug("Advance: Step forward.");
198
199 Vector<String> prev = getPreviousStateIds();
200 prev.add(getCurrentStateId());
201
202 setCurrentStateId(targetState);
203
204 ec.addAttr(result, "type", OPERATION_SUCCESSFUL, true);
205
206 return doc;
207 }
208
209 // TODO IMPLEMENT STEP BACK!
210
211 logger.warn("Advance: Cannot advance to '" + targetState + "'");
212
213 ec.addAttr(result, "type", OPERATION_FAILED, true);
151 214
152 return doc; 215 return doc;
153 } 216 }
154 217
155 218
199 return engine.getState(getCurrentStateId()); 262 return engine.getState(getCurrentStateId());
200 } 263 }
201 264
202 265
203 /** 266 /**
267 * Returns the vector of previous state identifiers.
268 *
269 * @return the vector of previous state identifiers.
270 */
271 protected Vector<String> getPreviousStateIds() {
272 return previousStateIds;
273 }
274
275
276 /**
204 * Adds a new StateData item to the data pool of this artifact. 277 * Adds a new StateData item to the data pool of this artifact.
205 * 278 *
206 * @param name the name of the data object. 279 * @param name the name of the data object.
207 * @param data the data object itself. 280 * @param data the data object itself.
208 */ 281 */
209 protected void addData(String name, StateData data) { 282 protected void addData(String name, StateData data) {
210 this.data.put(name, data); 283 this.data.put(name, data);
284 }
285
286
287 /**
288 * This method returns a specific StateData object that is stored in the
289 * data pool of this artifact.
290 *
291 * @param name The name of the data object.
292 *
293 * @return the StateData object if existing, otherwise null.
294 */
295 protected StateData getData(String name) {
296 return data.get(name);
211 } 297 }
212 298
213 299
214 /** 300 /**
215 * This method stores the data that is contained in the FEED document. 301 * This method stores the data that is contained in the FEED document.
251 // TODO ADD INPUT VALIDATION! 337 // TODO ADD INPUT VALIDATION!
252 addData(name, new DefaultStateData(name, null, null, value)); 338 addData(name, new DefaultStateData(name, null, null, value));
253 } 339 }
254 } 340 }
255 } 341 }
342
343
344 /**
345 * This method fills a state object with the data that have been inserted to
346 * this artifact. This is necessary to use the isStateReachable() method,
347 * because the Transitions need to know about the inserted data.
348 *
349 * @param state The state that needs to be filled with data.
350 *
351 * @return the filled state.
352 */
353 protected State fillState(State state) {
354 Map<String, StateData> stateData = state.getData();
355 Set<String> keys = stateData.keySet();
356
357 for (String key: keys) {
358 StateData tmp = getData(key);
359
360 if (tmp != null) {
361 StateData data = stateData.get(key);
362 data.setValue(tmp.getValue());
363 }
364 }
365
366 return state;
367 }
368
369
370 /**
371 * Determines if the state with the identifier <i>stateId</i> is reachable
372 * from the current state. The determination itself takes place in the
373 * TransitionEngine.
374 *
375 * @param stateId The identifier of a state.
376 * @param context The context object.
377 *
378 * @return true, if the state specified by <i>stateId</i> is reacahble,
379 * otherwise false.
380 */
381 protected boolean isStateReachable(String stateId, Object context) {
382 logger.debug("Determine if the state '" + stateId + "' is reachable.");
383
384 FLYSContext flysContext = getFlysContext(context);
385
386 State currentState = fillState(getCurrentState(context));
387 StateEngine sEngine = (StateEngine) flysContext.get(
388 FLYSContext.STATE_ENGINE_KEY);
389
390 TransitionEngine tEngine = (TransitionEngine) flysContext.get(
391 FLYSContext.TRANSITION_ENGINE_KEY);
392
393 return tEngine.isStateReachable(stateId, currentState, sEngine);
394 }
256 } 395 }
257 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : 396 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org