Keith Donald
2008-04-19 19:33:52 +00:00
parent 74e1a8ae46
commit dd8fffa18b
7 changed files with 49 additions and 38 deletions

View File

@@ -21,6 +21,7 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.springframework.binding.collection.MapAccessor;
@@ -232,6 +233,18 @@ public class LocalAttributeMap implements MutableAttributeMap, Serializable {
return this;
}
public MutableAttributeMap removeAll(MutableAttributeMap attributes) {
if (attributes == null) {
return this;
}
Iterator it = attributes.asMap().keySet().iterator();
Map internal = getMapInternal();
while (it.hasNext()) {
internal.remove(it.next());
}
return this;
}
public Object remove(String attributeName) {
return getMapInternal().remove(attributeName);
}

View File

@@ -45,6 +45,13 @@ public interface MutableAttributeMap extends AttributeMap {
*/
public MutableAttributeMap putAll(AttributeMap attributes);
/**
* Remove all attributes in the map provided from this map.
* @param attributes the attributes to remove from this map
* @return this, to support call chaining
*/
public MutableAttributeMap removeAll(MutableAttributeMap attributes);
/**
* Remove an attribute from this map.
* @param attributeName the name of the attribute to remove

View File

@@ -18,7 +18,7 @@ package org.springframework.webflow.engine;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.action.MultiAction;
import org.springframework.webflow.execution.Action;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
@@ -43,7 +43,6 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
* <p>
* The name attribute is often used as a qualifier for an action's result event, and is typically used to allow the
* flow to respond to a specific action's outcome within a larger action execution chain.
* @see ActionState
*/
public static final String NAME_ATTRIBUTE = "name";
@@ -51,8 +50,7 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
* The action execution method attribute ("method").
* <p>
* The method property is a hint about what method should be invoked; for example, the name of a specific target
* method on a {@link org.springframework.webflow.action.MultiAction multi action}.
* @see ActionState
* method on a {@link MultiAction multi-action}.
*/
public static final String METHOD_ATTRIBUTE = "method";
@@ -139,14 +137,12 @@ public class AnnotatedAction extends AnnotatedObject implements Action {
}
public Event execute(RequestContext context) throws Exception {
AttributeMap originalAttributes = getAttributes();
try {
context.setAttributes(getAttributes());
context.getAttributes().putAll(getAttributes());
Event result = getTargetAction().execute(context);
return postProcessResult(result);
} finally {
// restore original attributes
context.setAttributes(originalAttributes);
context.getAttributes().removeAll(getAttributes());
}
}

View File

@@ -18,8 +18,6 @@ package org.springframework.webflow.engine.impl;
import org.springframework.binding.message.MessageContext;
import org.springframework.core.style.ToStringCreator;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.CollectionUtils;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.core.collection.ParameterMap;
@@ -70,10 +68,9 @@ class RequestControlContextImpl implements RequestControlContext {
private LocalAttributeMap requestScope = new LocalAttributeMap();
/**
* Holder for contextual properties describing the currently executing request; never null, initially empty and
* immutable.
* Holder for contextual properties describing the currently executing request; never null, initially empty.
*/
private AttributeMap attributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP;
private LocalAttributeMap attributes = new LocalAttributeMap();
/**
* The current event being processed by this flow; initially null.
@@ -157,18 +154,10 @@ class RequestControlContextImpl implements RequestControlContext {
return currentTransition;
}
public AttributeMap getAttributes() {
public MutableAttributeMap getAttributes() {
return attributes;
}
public void setAttributes(AttributeMap attributes) {
if (attributes == null) {
this.attributes = CollectionUtils.EMPTY_ATTRIBUTE_MAP;
} else {
this.attributes = attributes;
}
}
// implementing RequestControlContext
public String getFlowExecutionUrl() {

View File

@@ -17,7 +17,6 @@ package org.springframework.webflow.execution;
import org.springframework.binding.message.MessageContext;
import org.springframework.webflow.context.ExternalContext;
import org.springframework.webflow.core.collection.AttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.core.collection.ParameterMap;
import org.springframework.webflow.definition.FlowDefinition;
@@ -175,17 +174,11 @@ public interface RequestContext {
public TransitionDefinition getCurrentTransition();
/**
* Returns a context map for accessing arbitrary attributes about the state of the current request. These attributes
* may be used to influence flow execution behavior.
* @return the current attributes of this request, or empty if not set
* Returns a context map for accessing attributes about the state of the current request. These attributes may be
* used to influence flow execution behavior.
* @return the current attributes of this request, or empty if none are set
*/
public AttributeMap getAttributes();
/**
* Set the contextual attributes describing the state of this request. Overwrites any pre-existing collection.
* @param attributes the attributes
*/
public void setAttributes(AttributeMap attributes);
public MutableAttributeMap getAttributes();
/**
* Returns the context-relative URL of this flow execution. Needed by response writers that write out the URL of

View File

@@ -166,14 +166,10 @@ public class MockRequestContext implements RequestContext {
return currentTransition;
}
public AttributeMap getAttributes() {
public MutableAttributeMap getAttributes() {
return attributes;
}
public void setAttributes(AttributeMap attributes) {
this.attributes.replaceWith(attributes);
}
public String getFlowExecutionUrl() {
if (flowExecutionContext.getKey() == null) {
throw new IllegalStateException(

View File

@@ -18,6 +18,7 @@ package org.springframework.webflow.engine;
import junit.framework.TestCase;
import org.springframework.webflow.action.AbstractAction;
import org.springframework.webflow.engine.AnnotatedAction;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.TestAction;
@@ -47,6 +48,22 @@ public class AnnotedActionTests extends TestCase {
}
});
assertEquals("success", action.execute(context).getId());
assertEquals(0, context.getAttributes().size());
}
public void testExecuteWithChainOfCustomAttributes() throws Exception {
AnnotatedAction action2 = new AnnotatedAction(action);
action2.getAttributes().put("attr2", "value");
action.getAttributes().put("attr", "value");
action.setTargetAction(new AbstractAction() {
protected Event doExecute(RequestContext context) throws Exception {
assertEquals("value", context.getAttributes().getString("attr"));
assertEquals("value", context.getAttributes().getString("attr2"));
return success();
}
});
assertEquals("success", action2.execute(context).getId());
assertEquals(0, context.getAttributes().size());
}
public void testExecuteWithName() throws Exception {