1 /* 2 * Copyright (c) 2002-2007 by OpenSymphony 3 * All rights reserved. 4 */ 5 package com.opensymphony.xwork2.interceptor; 6 7 import com.opensymphony.xwork2.ActionInvocation; 8 import com.opensymphony.xwork2.Unchainable; 9 import com.opensymphony.xwork2.inject.Inject; 10 import com.opensymphony.xwork2.util.CompoundRoot; 11 import com.opensymphony.xwork2.util.ValueStack; 12 import com.opensymphony.xwork2.util.logging.Logger; 13 import com.opensymphony.xwork2.util.logging.LoggerFactory; 14 import com.opensymphony.xwork2.util.reflection.ReflectionProvider; 15 16 import java.util; 17 18 19 /** 20 * <!-- START SNIPPET: description --> 21 * 22 * An interceptor that copies all the properties of every object in the value stack to the currently executing object, 23 * except for any object that implements {@link Unchainable}. A collection of optional <i>includes</i> and 24 * <i>excludes</i> may be provided to control how and which parameters are copied. Only includes or excludes may be 25 * specified. Specifying both results in undefined behavior. See the javadocs for {@link ReflectionProvider#copy(Object, Object, 26 * java.util.Map, java.util.Collection, java.util.Collection)} for more information. 27 * 28 * <p/> 29 * <b>Note:</b> It is important to remember that this interceptor does nothing if there are no objects already on the stack. 30 * <br/>This means two things: 31 * <br/><b>One</b>, you can safely apply it to all your actions without any worry of adverse affects. 32 * <br/><b/>Two</b>, it is up to you to ensure an object exists in the stack prior to invoking this action. The most typical way this is done 33 * is through the use of the <b>chain</b> result type, which combines with this interceptor to make up the action 34 * chaining feature. 35 * 36 * <!-- END SNIPPET: description --> 37 * 38 * <p/> <u>Interceptor parameters:</u> 39 * 40 * <!-- START SNIPPET: parameters --> 41 * 42 * <ul> 43 * 44 * <li>excludes (optional) - the list of parameter names to exclude from copying (all others will be included).</li> 45 * 46 * <li>includes (optional) - the list of parameter names to include when copying (all others will be excluded).</li> 47 * 48 * </ul> 49 * 50 * <!-- END SNIPPET: parameters --> 51 * 52 * <p/> <u>Extending the interceptor:</u> 53 * 54 * <p/> 55 * 56 * <!-- START SNIPPET: extending --> 57 * 58 * There are no known extension points to this interceptor. 59 * 60 * <!-- END SNIPPET: extending --> 61 * 62 * <p/> <u>Example code:</u> 63 * 64 * <pre> 65 * <!-- START SNIPPET: example --> 66 * 67 * <action name="someAction" class="com.examples.SomeAction"> 68 * <interceptor-ref name="basicStack"/> 69 * <result name="success" type="chain">otherAction</result> 70 * </action> 71 * 72 * <action name="otherAction" class="com.examples.OtherAction"> 73 * <interceptor-ref name="chain"/> 74 * <interceptor-ref name="basicStack"/> 75 * <result name="success">good_result.ftl</result> 76 * </action> 77 * 78 * <!-- END SNIPPET: example --> 79 * </pre> 80 * 81 * @see com.opensymphony.xwork2.ActionChainResult 82 * @author mrdon 83 * @author tm_jee ( tm_jee(at)yahoo.co.uk ) 84 */ 85 public class ChainingInterceptor extends AbstractInterceptor { 86 87 private static final Logger LOG = LoggerFactory.getLogger(ChainingInterceptor.class); 88 89 protected Collection<String> excludes; 90 protected Collection<String> includes; 91 92 protected ReflectionProvider reflectionProvider; 93 94 @Inject 95 public void setReflectionProvider(ReflectionProvider prov) { 96 this.reflectionProvider = prov; 97 } 98 99 @Override 100 public String intercept(ActionInvocation invocation) throws Exception { 101 ValueStack stack = invocation.getStack(); 102 CompoundRoot root = stack.getRoot(); 103 104 if (root.size() > 1) { 105 List<CompoundRoot> list = new ArrayList<CompoundRoot>(root); 106 list.remove(0); 107 Collections.reverse(list); 108 109 Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); 110 Iterator<CompoundRoot> iterator = list.iterator(); 111 int index = 1; // starts with 1, 0 has been removed 112 while (iterator.hasNext()) { 113 index = index + 1; 114 Object o = iterator.next(); 115 if (o != null) { 116 if (!(o instanceof Unchainable)) { 117 reflectionProvider.copy(o, invocation.getAction(), ctxMap, excludes, includes); 118 } 119 } 120 else { 121 LOG.warn("compound root element at index "+index+" is null"); 122 } 123 } 124 } 125 126 return invocation.invoke(); 127 } 128 129 /** 130 * Gets list of parameter names to exclude 131 * 132 * @return the exclude list 133 */ 134 public Collection<String> getExcludes() { 135 return excludes; 136 } 137 138 /** 139 * Sets the list of parameter names to exclude from copying (all others will be included). 140 * 141 * @param excludes the excludes list 142 */ 143 public void setExcludes(Collection<String> excludes) { 144 this.excludes = excludes; 145 } 146 147 /** 148 * Gets list of parameter names to include 149 * 150 * @return the include list 151 */ 152 public Collection<String> getIncludes() { 153 return includes; 154 } 155 156 /** 157 * Sets the list of parameter names to include when copying (all others will be excluded). 158 * 159 * @param includes the includes list 160 */ 161 public void setIncludes(Collection<String> includes) { 162 this.includes = includes; 163 } 164 165 }