Author: lukaszlenart Date: Wed Sep 15 14:12:26 2010 New Revision: 997345 URL: http://svn.apache.org/viewvc?rev=997345&view=rev Log: Solved WW-3488 - exclude copy Action's Errors and Messages from chain
Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ChainingInterceptorTest.java Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java?rev=997345&r1=997344&r2=997345&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java (original) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ChainingInterceptor.java Wed Sep 15 14:12:26 2010 @@ -26,12 +26,7 @@ import com.opensymphony.xwork2.util.logg import com.opensymphony.xwork2.util.logging.LoggerFactory; import com.opensymphony.xwork2.util.reflection.ReflectionProvider; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; /** @@ -104,6 +99,12 @@ public class ChainingInterceptor extends private static final Logger LOG = LoggerFactory.getLogger(ChainingInterceptor.class); + private static final String ACTION_ERRORS = "actionErrors"; + private static final String ACTION_MESSAGES = "actionMessages"; + + private boolean copyMessages = false; + private boolean copyErrors = false; + protected Collection<String> excludes; protected Collection<String> includes; @@ -114,37 +115,67 @@ public class ChainingInterceptor extends this.reflectionProvider = prov; } + @Inject(value = "struts.xwork.chaining.copyErrors", required = false) + public void setCopyErrors(String copyErrors) { + this.copyErrors = "true".equalsIgnoreCase(copyErrors); + } + + @Inject(value = "struts.xwork.chaining.copyMessages", required = false) + public void setCopyMessages(String copyMessages) { + this.copyMessages = "true".equalsIgnoreCase(copyMessages); + } + @Override public String intercept(ActionInvocation invocation) throws Exception { ValueStack stack = invocation.getStack(); CompoundRoot root = stack.getRoot(); + if (shouldCopyStack(invocation, root)) { + copyStack(invocation, root); + } + return invocation.invoke(); + } - if (root.size() > 1 && isChainResult(invocation)) { - List<CompoundRoot> list = new ArrayList<CompoundRoot>(root); - list.remove(0); - Collections.reverse(list); - - Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); - Iterator<CompoundRoot> iterator = list.iterator(); - int index = 1; // starts with 1, 0 has been removed - while (iterator.hasNext()) { - index = index + 1; - Object o = iterator.next(); - if (o != null) { - if (!(o instanceof Unchainable)) { - reflectionProvider.copy(o, invocation.getAction(), ctxMap, excludes, includes); - } - } else { - LOG.warn("compound root element at index " + index + " is null"); + private void copyStack(ActionInvocation invocation, CompoundRoot root) { + List list = prepareList(root); + Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); + for (Object object : list) { + if (shouldCopy(object)) { + reflectionProvider.copy(object, invocation.getAction(), ctxMap, prepareExcludes(), includes); + } + } + } + + private Collection<String> prepareExcludes() { + Collection<String> localExcludes = excludes; + if (!copyErrors || !copyMessages) { + if (localExcludes == null) { + localExcludes = new HashSet<String>(); + if (!copyErrors) { + localExcludes.add(ACTION_ERRORS); + } + if (!copyMessages) { + localExcludes.add(ACTION_MESSAGES); } } } - return invocation.invoke(); + return localExcludes; + } + + private boolean shouldCopy(Object o) { + return o != null && !(o instanceof Unchainable); + } + + @SuppressWarnings("unchecked") + private List prepareList(CompoundRoot root) { + List list = new ArrayList(root); + list.remove(0); + Collections.reverse(list); + return list; } - private boolean isChainResult(ActionInvocation invocation) throws Exception { + private boolean shouldCopyStack(ActionInvocation invocation, CompoundRoot root) throws Exception { Result result = invocation.getResult(); - return result != null && ActionChainResult.class.isAssignableFrom(result.getClass()); + return root.size() > 1 && (result == null || ActionChainResult.class.isAssignableFrom(result.getClass())); } /** @@ -180,7 +211,7 @@ public class ChainingInterceptor extends * @param includes the includes list */ public void setIncludes(Collection<String> includes) { - this.includes = includes; + this.includes.addAll(includes); } } Modified: struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ChainingInterceptorTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ChainingInterceptorTest.java?rev=997345&r1=997344&r2=997345&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ChainingInterceptorTest.java (original) +++ struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/interceptor/ChainingInterceptorTest.java Wed Sep 15 14:12:26 2010 @@ -19,10 +19,7 @@ import com.mockobjects.dynamic.Mock; import com.opensymphony.xwork2.*; import com.opensymphony.xwork2.util.ValueStack; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; +import java.util.*; /** @@ -45,7 +42,11 @@ public class ChainingInterceptorTest ext mockInvocation.matchAndReturn("getAction", action2); stack.push(action1); stack.push(action2); + interceptor.setCopyErrors("true"); + interceptor.setCopyMessages("true"); + interceptor.intercept(invocation); + assertEquals(action1.getActionErrors(), action2.getActionErrors()); action2.addActionError("bar"); assertEquals(1, action1.getActionErrors().size()); @@ -53,6 +54,24 @@ public class ChainingInterceptorTest ext assertTrue(action2.getActionErrors().contains("bar")); } + public void testActionErrorsNotCopiedAfterChain() throws Exception { + SimpleAction action1 = new SimpleAction(); + SimpleAction action2 = new SimpleAction(); + action1.addActionError("foo"); + mockInvocation.matchAndReturn("getAction", action2); + stack.push(action1); + stack.push(action2); + + interceptor.intercept(invocation); + + assertEquals(Collections.EMPTY_LIST, action2.getActionErrors()); + action2.addActionError("bar"); + assertEquals(1, action1.getActionErrors().size()); + assertEquals(1, action2.getActionErrors().size()); + assertTrue(action2.getActionErrors().contains("bar")); + assertFalse(action2.getActionErrors().contains("foo")); + } + public void testPropertiesChained() throws Exception { TestBean bean = new TestBean(); TestBeanAction action = new TestBeanAction(); @@ -62,7 +81,11 @@ public class ChainingInterceptorTest ext bean.setCount(1); stack.push(bean); stack.push(action); + interceptor.setCopyErrors("true"); + interceptor.setCopyMessages("true"); + interceptor.intercept(invocation); + assertEquals(bean.getBirth(), action.getBirth()); assertEquals(bean.getName(), action.getName()); assertEquals(bean.getCount(), action.getCount()); @@ -77,11 +100,15 @@ public class ChainingInterceptorTest ext bean.setCount(1); stack.push(bean); stack.push(action); + interceptor.setCopyErrors("true"); + interceptor.setCopyMessages("true"); Collection excludes = new ArrayList(); excludes.add("count"); interceptor.setExcludes(excludes); + interceptor.intercept(invocation); + assertEquals(bean.getBirth(), action.getBirth()); assertEquals(bean.getName(), action.getName()); assertEquals(0, action.getCount());