You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2011/12/02 17:33:45 UTC

svn commit: r1209569 [22/50] - in /struts/struts2/branches/STRUTS_3_X: apps/blank/src/main/java/example/ apps/blank/src/test/java/example/ apps/jboss-blank/src/main/java/example/ apps/jboss-blank/src/test/java/example/ apps/mailreader/src/main/java/mai...

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ModelDrivenInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ModelDrivenInterceptor.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ModelDrivenInterceptor.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ModelDrivenInterceptor.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.ModelDriven;
+import org.apache.struts2.xwork2.util.CompoundRoot;
+import org.apache.struts2.xwork2.util.ValueStack;
+
+
+/**
+ * <!-- START SNIPPET: description -->
+ *
+ * Watches for {@link ModelDriven} actions and adds the action's model on to the value stack.
+ *
+ * <p/> <b>Note:</b>  The ModelDrivenInterceptor must come before the both {@link StaticParametersInterceptor} and
+ * {@link ParametersInterceptor} if you want the parameters to be applied to the model.
+ * 
+ * <p/> <b>Note:</b>  The ModelDrivenInterceptor will only push the model into the stack when the
+ * model is not null, else it will be ignored.
+ *
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Interceptor parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ *
+ * <ul>
+ *
+ * <li>refreshModelBeforeResult - set to true if you want the model to be refreshed on the value stack after action
+ * execution and before result execution.  The setting is useful if you want to change the model instance during the
+ * action execution phase, like when loading it from the data layer.  This will result in getModel() being called at
+ * least twice.</li>
+ *
+ * </ul>
+ *
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Extending the interceptor:</u>
+ *
+ * <p/>
+ *
+ * <!-- START SNIPPET: extending -->
+ *
+ * There are no known extension points to this interceptor.
+ *
+ * <!-- END SNIPPET: extending -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
+ *     &lt;interceptor-ref name="modelDriven"/&gt;
+ *     &lt;interceptor-ref name="basicStack"/&gt;
+ *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
+ * &lt;/action&gt;
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ * 
+ * @author tm_jee
+ * @version $Date: 2011-12-02 12:24:48 +0100 (Fri, 02 Dec 2011) $ $Id: ModelDrivenInterceptor.java 1209415 2011-12-02 11:24:48Z lukaszlenart $
+ */
+public class ModelDrivenInterceptor extends AbstractInterceptor {
+
+    protected boolean refreshModelBeforeResult = false;
+
+    public void setRefreshModelBeforeResult(boolean val) {
+        this.refreshModelBeforeResult = val;
+    }
+
+    @Override
+    public String intercept(ActionInvocation invocation) throws Exception {
+        Object action = invocation.getAction();
+
+        if (action instanceof ModelDriven) {
+            ModelDriven modelDriven = (ModelDriven) action;
+            ValueStack stack = invocation.getStack();
+            Object model = modelDriven.getModel();
+            if (model !=  null) {
+            	stack.push(model);
+            }
+            if (refreshModelBeforeResult) {
+                invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
+            }
+        }
+        return invocation.invoke();
+    }
+
+    /**
+     * Refreshes the model instance on the value stack, if it has changed
+     */
+    protected static class RefreshModelBeforeResult implements PreResultListener {
+        private Object originalModel = null;
+        protected ModelDriven action;
+
+
+        public RefreshModelBeforeResult(ModelDriven action, Object model) {
+            this.originalModel = model;
+            this.action = action;
+        }
+
+        public void beforeResult(ActionInvocation invocation, String resultCode) {
+            ValueStack stack = invocation.getStack();
+            CompoundRoot root = stack.getRoot();
+
+            boolean needsRefresh = true;
+            Object newModel = action.getModel();
+
+            // Check to see if the new model instance is already on the stack
+            for (Object item : root) {
+                if (item.equals(newModel)) {
+                    needsRefresh = false;
+                }
+            }
+
+            // Add the new model on the stack
+            if (needsRefresh) {
+
+                // Clear off the old model instance
+                if (originalModel != null) {
+                    root.remove(originalModel);
+                }
+                if (newModel != null) {
+                    stack.push(newModel);
+                }
+            }
+        }
+    }
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/NoParameters.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/NoParameters.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/NoParameters.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/NoParameters.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2002-2007,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+
+/**
+ * Marker interface to incidate no auto setting of parameters.
+ * <p/>
+ * This marker interface should be implemented by actions that do not want any
+ * request parameters set on them automatically (by the ParametersInterceptor).
+ * This may be useful if one is using the action tag and want to supply
+ * the parameters to the action manually using the param tag.
+ * It may also be useful if one for security reasons wants to make sure that
+ * parameters cannot be set by malicious users.
+ *
+ * @author Dick Zetterberg (dick@transitor.se)
+ */
+public interface NoParameters {
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterFilterInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterFilterInterceptor.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterFilterInterceptor.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterFilterInterceptor.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2002-2007,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.util.TextParseUtil;
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * <!-- START SNIPPET: description -->
+ *
+ * The Parameter Filter Interceptor blocks parameters from getting
+ * to the rest of the stack or your action. You can use multiple 
+ * parameter filter interceptors for a given action, so, for example,
+ * you could use one in your default stack that filtered parameters
+ * you wanted blocked from every action and those you wanted blocked 
+ * from an individual action you could add an additional interceptor
+ * for each action.
+ * 
+ * <!-- END SNIPPET: description -->
+ * 
+ * <!-- START SNIPPET: parameters -->
+ *
+ * <ul>
+ * <li>allowed - a comma delimited list of parameter prefixes
+ *  that are allowed to pass to the action</li>
+ * <li>blocked - a comma delimited list of parameter prefixes 
+ * that are not allowed to pass to the action</li>
+ * <li>defaultBlock - boolean (default to false) whether by
+ * default a given parameter is blocked. If true, then a parameter
+ * must have a prefix in the allowed list in order to be able 
+ * to pass to the action
+ * </ul>
+ * 
+ * <p>The way parameters are filtered for the least configuration is that
+ * if a string is in the allowed or blocked lists, then any parameter
+ * that is a member of the object represented by the parameter is allowed
+ * or blocked respectively.</p>
+ * 
+ * <p>For example, if the parameters are:
+ * <ul>
+ * <li>blocked: person,person.address.createDate,personDao</li>
+ * <li>allowed: person.address</li>
+ * <li>defaultBlock: false</li>
+ * </ul>
+ * <br>
+ * The parameters person.name, person.phoneNum etc would be blocked 
+ * because 'person' is in the blocked list. However, person.address.street
+ * and person.address.city would be allowed because person.address is
+ * in the allowed list (the longer string determines permissions).</p> 
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <!-- START SNIPPET: extending -->
+ * There are no known extension points to this interceptor.
+ * <!-- END SNIPPET: extending -->
+ * 
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &lt;interceptors&gt;
+ *   ...
+ *   &lt;interceptor name="parameterFilter" class="org.apache.struts2.xwork2.interceptor.ParameterFilterInterceptor"/&gt;
+ *   ...
+ * &lt;/interceptors&gt;
+ * 
+ * &lt;action ....&gt;
+ *   ...
+ *   &lt;interceptor-ref name="parameterFilter"&gt;
+ *     &lt;param name="blocked"&gt;person,person.address.createDate,personDao&lt;/param&gt;
+ *   &lt;/interceptor-ref&gt;
+ *   ...
+ * &lt;/action&gt;
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ * 
+ * @author Gabe
+ */
+public class ParameterFilterInterceptor extends AbstractInterceptor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ParameterFilterInterceptor.class);
+
+    private Collection<String> allowed;
+    private Collection<String> blocked;
+    private Map<String, Boolean> includesExcludesMap;
+    private boolean defaultBlock = false;
+
+    @Override
+    public String intercept(ActionInvocation invocation) throws Exception {
+
+        Map<String, Object> parameters = invocation.getInvocationContext().getParameters();
+        HashSet<String> paramsToRemove = new HashSet<String>();
+
+        Map<String, Boolean> includesExcludesMap = getIncludesExcludesMap();
+
+        for (String param : parameters.keySet()) {
+            boolean currentAllowed = !isDefaultBlock();
+
+            for (String currRule : includesExcludesMap.keySet()) {
+                if (param.startsWith(currRule)
+                        && (param.length() == currRule.length()
+                        || isPropSeperator(param.charAt(currRule.length())))) {
+                    currentAllowed = includesExcludesMap.get(currRule).booleanValue();
+                }
+            }
+            if (!currentAllowed) {
+                paramsToRemove.add(param);
+            }
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Params to remove: " + paramsToRemove);
+        }
+
+        for (Object aParamsToRemove : paramsToRemove) {
+            parameters.remove(aParamsToRemove);
+        }
+
+        return invocation.invoke();
+    }
+
+    /**
+     * Tests if the given char is a property seperator char <code>.([</code>.
+     *
+     * @param c the char
+     * @return <tt>true</tt>, if char is property separator, <tt>false</tt> otherwise.
+     */
+    private static boolean isPropSeperator(char c) {
+        return c == '.' || c == '(' || c == '[';
+    }
+
+    private Map<String, Boolean> getIncludesExcludesMap() {
+        if (this.includesExcludesMap == null) {
+            this.includesExcludesMap = new TreeMap<String, Boolean>();
+
+            if (getAllowedCollection() != null) {
+                for (String e : getAllowedCollection()) {
+                    this.includesExcludesMap.put(e, Boolean.TRUE);
+                }
+            }
+            if (getBlockedCollection() != null) {
+                for (String b : getBlockedCollection()) {
+                    this.includesExcludesMap.put(b, Boolean.FALSE);
+                }
+            }
+        }
+
+        return this.includesExcludesMap;
+    }
+
+    /**
+     * @return Returns the defaultBlock.
+     */
+    public boolean isDefaultBlock() {
+        return defaultBlock;
+    }
+
+    /**
+     * @param defaultExclude The defaultExclude to set.
+     */
+    public void setDefaultBlock(boolean defaultExclude) {
+        this.defaultBlock = defaultExclude;
+    }
+
+    /**
+     * @return Returns the blocked.
+     */
+    public Collection<String> getBlockedCollection() {
+        return blocked;
+    }
+
+    /**
+     * @param blocked The blocked to set.
+     */
+    public void setBlockedCollection(Collection<String> blocked) {
+        this.blocked = blocked;
+    }
+
+    /**
+     * @param blocked The blocked paramters as comma separated String.
+     */
+    public void setBlocked(String blocked) {
+        setBlockedCollection(asCollection(blocked));
+    }
+
+    /**
+     * @return Returns the allowed.
+     */
+    public Collection<String> getAllowedCollection() {
+        return allowed;
+    }
+
+    /**
+     * @param allowed The allowed to set.
+     */
+    public void setAllowedCollection(Collection<String> allowed) {
+        this.allowed = allowed;
+    }
+
+    /**
+     * @param allowed The allowed paramters as comma separated String.
+     */
+    public void setAllowed(String allowed) {
+        setAllowedCollection(asCollection(allowed));
+    }
+
+    /**
+     * Return a collection from the comma delimited String.
+     *
+     * @param commaDelim the comma delimited String.
+     * @return A collection from the comma delimited String. Returns <tt>null</tt> if the string is empty.
+     */
+    private Collection<String> asCollection(String commaDelim) {
+        if (commaDelim == null || commaDelim.trim().length() == 0) {
+            return null;
+        }
+        return TextParseUtil.commaDelimitedStringToSet(commaDelim);
+    }
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterNameAware.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterNameAware.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterNameAware.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterNameAware.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-2007,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+/**
+ * <!-- START SNIPPET: javadoc -->
+ *
+ * This interface is implemented by actions that want to declare acceptable parameters. Works in conjunction with {@link
+ * ParametersInterceptor}. For example, actions may want to create a whitelist of parameters they will accept or a
+ * blacklist of paramters they will reject to prevent clients from setting other unexpected (and possibly dangerous)
+ * parameters.
+ *
+ * <!-- END SNIPPET: javadoc -->
+ *
+ * @author Bob Lee (crazybob@google.com)
+ */
+public interface ParameterNameAware {
+
+    /**
+     * Tests if the the action will accept the parameter with the given name.
+     *
+     * @param parameterName  the parameter name
+     * @return <tt> if accepted, <tt>false</tt> otherwise
+     */
+    boolean acceptableParameterName(String parameterName);
+    
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterRemoverInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterRemoverInterceptor.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterRemoverInterceptor.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParameterRemoverInterceptor.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2002-2007,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.util.TextParseUtil;
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <!-- START SNIPPET: description -->
+ * This is a simple XWork interceptor that allows parameters (matching
+ * one of the paramNames attribute csv value) to be 
+ * removed from the parameter map if they match a certain value
+ * (matching one of the paramValues attribute csv value), before they 
+ * are set on the action. A typical usage would be to want a dropdown/select 
+ * to map onto a boolean value on an action. The select had the options 
+ * none, yes and no with values -1, true and false. The true and false would 
+ * map across correctly. However the -1 would be set to false. 
+ * This was not desired as one might needed the value on the action to stay null. 
+ * This interceptor fixes this by preventing the parameter from ever reaching 
+ * the action.
+ * <!-- END SNIPPET: description -->
+ * 
+ * 
+ * <!-- START SNIPPET: parameters -->
+ * <ul>
+ * 	<li>paramNames - A comma separated value (csv) indicating the parameter name 
+ * 								    whose param value should be considered that if they match any of the
+ *                                     comma separated value (csv) from paramValues attribute, shall be 
+ *                                     removed from the parameter map such that they will not be applied
+ *                                     to the action</li>
+ * 	<li>paramValues - A comma separated value (csv) indicating the parameter value that if 
+ * 							      matched shall have its parameter be removed from the parameter map 
+ * 							      such that they will not be applied to the action</li>
+ * </ul>
+ * <!-- END SNIPPET: parameters -->
+ * 
+ * 
+ * <!-- START SNIPPET: extending -->
+ * No intended extension point
+ * <!-- END SNIPPET: extending -->
+ * 
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ *	
+ * &lt;action name="sample" class="org.martingilday.Sample"&gt;
+ * 	&lt;interceptor-ref name="paramRemover"&gt;
+ *   		&lt;param name="paramNames"&gt;aParam,anotherParam&lt;/param&gt;
+ *   		&lt;param name="paramValues"&gt;--,-1&lt;/param&gt;
+ * 	&lt;/interceptor-ref&gt;
+ * 	&lt;interceptor-ref name="defaultStack" /&gt;
+ * 	...
+ * &lt;/action&gt;
+ *  
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *  
+ *  
+ * @author martin.gilday
+ */
+public class ParameterRemoverInterceptor extends AbstractInterceptor {
+
+	private static final Logger LOG = LoggerFactory.getLogger(ParameterRemoverInterceptor.class);
+
+	private static final long serialVersionUID = 1;
+
+	private Set<String> paramNames = Collections.emptySet();
+
+	private Set<String> paramValues = Collections.emptySet();
+
+	
+	/**
+	 * Decide if the parameter should be removed from the parameter map based on
+	 * <code>paramNames</code> and <code>paramValues</code>.
+	 * 
+	 * @see AbstractInterceptor
+	 */
+	@Override
+	public String intercept(ActionInvocation invocation) throws Exception {
+		if (!(invocation.getAction() instanceof NoParameters)
+				&& (null != this.paramNames)) {
+			ActionContext ac = invocation.getInvocationContext();
+			final Map<String, Object> parameters = ac.getParameters();
+
+			if (parameters != null) {
+                for (String removeName : paramNames) {
+                    // see if the field is in the parameter map
+                    if (parameters.containsKey(removeName)) {
+
+                        try {
+                            String[] values = (String[]) parameters
+                                    .get(removeName);
+                            String value = values[0];
+                            if (null != value && this.paramValues.contains(value)) {
+                                parameters.remove(removeName);
+                            }
+                        } catch (Exception e) {
+                            LOG.error("Failed to convert parameter to string", e);
+                        }
+                    }
+                }
+			}
+		}
+		return invocation.invoke();
+	}
+
+	/**
+	 * Allows <code>paramNames</code> attribute to be set as comma-separated-values (csv).
+	 * 
+	 * @param paramNames the paramNames to set
+	 */
+	public void setParamNames(String paramNames) {
+		this.paramNames = TextParseUtil.commaDelimitedStringToSet(paramNames);
+	}
+
+
+	/**
+	 * Allows <code>paramValues</code> attribute to be set as a comma-separated-values (csv).
+	 * 
+	 * @param paramValues the paramValues to set
+	 */
+	public void setParamValues(String paramValues) {
+		this.paramValues = TextParseUtil.commaDelimitedStringToSet(paramValues);
+	}
+}
+

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParametersInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParametersInterceptor.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParametersInterceptor.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ParametersInterceptor.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2002-2007,2009 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.ValidationAware;
+import org.apache.struts2.xwork2.inject.Inject;
+import org.apache.struts2.xwork2.util.ClearableValueStack;
+import org.apache.struts2.xwork2.util.LocalizedTextUtil;
+import org.apache.struts2.xwork2.util.MemberAccessValueStack;
+import org.apache.struts2.xwork2.util.TextParseUtil;
+import org.apache.struts2.xwork2.util.ValueStack;
+import org.apache.struts2.xwork2.util.ValueStackFactory;
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+import org.apache.struts2.xwork2.util.reflection.ReflectionContextState;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * <!-- START SNIPPET: description -->
+ * This interceptor sets all parameters on the value stack.
+ * <p/>
+ * This interceptor gets all parameters from {@link ActionContext#getParameters()} and sets them on the value stack by
+ * calling {@link ValueStack#setValue(String, Object)}, typically resulting in the values submitted in a form
+ * request being applied to an action in the value stack. Note that the parameter map must contain a String key and
+ * often containers a String[] for the value.
+ * <p/>
+ * <p/> The interceptor takes one parameter named 'ordered'. When set to true action properties are guaranteed to be
+ * set top-down which means that top action's properties are set first. Then it's subcomponents properties are set.
+ * The reason for this order is to enable a 'factory' pattern. For example, let's assume that one has an action
+ * that contains a property named 'modelClass' that allows to choose what is the underlying implementation of model.
+ * By assuring that modelClass property is set before any model properties are set, it's possible to choose model
+ * implementation during action.setModelClass() call. Similiarily it's possible to use action.setPrimaryKey()
+ * property set call to actually load the model class from persistent storage. Without any assumption on parameter
+ * order you have to use patterns like 'Preparable'.
+ * <p/>
+ * <p/> Because parameter names are effectively OGNL statements, it is important that security be taken in to account.
+ * This interceptor will not apply any values in the parameters map if the expression contains an assignment (=),
+ * multiple expressions (,), or references any objects in the context (#). This is all done in the {@link
+ * #acceptableName(String)} method. In addition to this method, if the action being invoked implements the {@link
+ * ParameterNameAware} interface, the action will be consulted to determine if the parameter should be set.
+ * <p/>
+ * <p/> In addition to these restrictions, a flag ({@link org.apache.struts2.xwork2.util.reflection.ReflectionContextState#DENY_METHOD_EXECUTION}) is set such that
+ * no methods are allowed to be invoked. That means that any expression such as <i>person.doSomething()</i> or
+ * <i>person.getName()</i> will be explicitely forbidden. This is needed to make sure that your application is not
+ * exposed to attacks by malicious users.
+ * <p/>
+ * <p/> While this interceptor is being invoked, a flag ({@link org.apache.struts2.xwork2.util.reflection.ReflectionContextState#CREATE_NULL_OBJECTS}) is turned
+ * on to ensure that any null reference is automatically created - if possible. See the type conversion documentation
+ * and the {@link org.apache.struts2.xwork2.conversion.impl.InstantiatingNullHandler} javadocs for more information.
+ * <p/>
+ * <p/> Finally, a third flag ({@link org.apache.struts2.xwork2.conversion.impl.XWorkConverter#REPORT_CONVERSION_ERRORS}) is set that indicates any errors when
+ * converting the the values to their final data type (String[] -&gt; int) an unrecoverable error occured. With this
+ * flag set, the type conversion errors will be reported in the action context. See the type conversion documentation
+ * and the {@link org.apache.struts2.xwork2.conversion.impl.XWorkConverter} javadocs for more information.
+ * <p/>
+ * <p/> If you are looking for detailed logging information about your parameters, turn on DEBUG level logging for this
+ * interceptor. A detailed log of all the parameter keys and values will be reported.
+ * <p/>
+ * <p/>
+ * <b>Note:</b> Since XWork 2.0.2, this interceptor extends {@link MethodFilterInterceptor}, therefore being
+ * able to deal with excludeMethods / includeMethods parameters. See [Workflow Interceptor]
+ * (class {@link DefaultWorkflowInterceptor}) for documentation and examples on how to use this feature.
+ * <p/>
+ * <!-- END SNIPPET: description -->
+ * <p/>
+ * <p/> <u>Interceptor parameters:</u>
+ * <p/>
+ * <!-- START SNIPPET: parameters -->
+ * <p/>
+ * <ul>
+ * <p/>
+ * <li>ordered - set to true if you want the top-down property setter behaviour</li>
+ * <p/>
+ * </ul>
+ * <p/>
+ * <!-- END SNIPPET: parameters -->
+ * <p/>
+ * <p/> <u>Extending the interceptor:</u>
+ * <p/>
+ * <!-- START SNIPPET: extending -->
+ * <p/>
+ * <p/> The best way to add behavior to this interceptor is to utilize the {@link ParameterNameAware} interface in your
+ * actions. However, if you wish to apply a global rule that isn't implemented in your action, then you could extend
+ * this interceptor and override the {@link #acceptableName(String)} method.
+ * <p/>
+ * <!-- END SNIPPET: extending -->
+ * <p/>
+ * <p/> <u>Example code:</u>
+ * <p/>
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
+ *     &lt;interceptor-ref name="params"/&gt;
+ *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
+ * &lt;/action&gt;
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author Patrick Lightbody
+ */
+public class ParametersInterceptor extends MethodFilterInterceptor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ParametersInterceptor.class);
+
+    boolean ordered = false;
+    Set<Pattern> excludeParams = Collections.emptySet();
+    Set<Pattern> acceptParams = Collections.emptySet();
+    static boolean devMode = false;
+
+    // Allowed names of parameters
+    private String acceptedParamNames = "[a-zA-Z0-9\\.\\]\\[\\(\\)_'\\s]+";
+    private Pattern acceptedPattern = Pattern.compile(acceptedParamNames);
+
+    private ValueStackFactory valueStackFactory;
+
+    @Inject
+    public void setValueStackFactory(ValueStackFactory valueStackFactory) {
+        this.valueStackFactory = valueStackFactory;
+    }
+
+    @Inject("devMode")
+    public static void setDevMode(String mode) {
+        devMode = "true".equals(mode);
+    }
+
+    public void setAcceptParamNames(String commaDelim) {
+        Collection<String> acceptPatterns = asCollection(commaDelim);
+        if (acceptPatterns != null) {
+            acceptParams = new HashSet<Pattern>();
+            for (String pattern : acceptPatterns) {
+                acceptParams.add(Pattern.compile(pattern));
+            }
+        }
+    }
+
+    static private int countOGNLCharacters(String s) {
+        int count = 0;
+        for (int i = s.length() - 1; i >= 0; i--) {
+            char c = s.charAt(i);
+            if (c == '.' || c == '[') count++;
+        }
+        return count;
+    }
+
+    /**
+     * Compares based on number of '.' and '[' characters (fewer is higher)
+     */
+    static final Comparator<String> rbCollator = new Comparator<String>() {
+        public int compare(String s1, String s2) {
+            int l1 = countOGNLCharacters(s1),
+                l2 = countOGNLCharacters(s2);
+            return l1 < l2 ? -1 : (l2 < l1 ? 1 : s1.compareTo(s2));
+        }
+
+    };
+
+    @Override
+    public String doIntercept(ActionInvocation invocation) throws Exception {
+        Object action = invocation.getAction();
+        if (!(action instanceof NoParameters)) {
+            ActionContext ac = invocation.getInvocationContext();
+            final Map<String, Object> parameters = retrieveParameters(ac);
+
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Setting params " + getParameterLogMap(parameters));
+            }
+
+            if (parameters != null) {
+                Map<String, Object> contextMap = ac.getContextMap();
+                try {
+                    ReflectionContextState.setCreatingNullObjects(contextMap, true);
+                    ReflectionContextState.setDenyMethodExecution(contextMap, true);
+                    ReflectionContextState.setReportingConversionErrors(contextMap, true);
+
+                    ValueStack stack = ac.getValueStack();
+                    setParameters(action, stack, parameters);
+                } finally {
+                    ReflectionContextState.setCreatingNullObjects(contextMap, false);
+                    ReflectionContextState.setDenyMethodExecution(contextMap, false);
+                    ReflectionContextState.setReportingConversionErrors(contextMap, false);
+                }
+            }
+        }
+        return invocation.invoke();
+    }
+
+    /**
+     * Gets the parameter map to apply from wherever appropriate
+     *
+     * @param ac The action context
+     * @return The parameter map to apply
+     */
+    protected Map<String, Object> retrieveParameters(ActionContext ac) {
+        return ac.getParameters();
+    }
+
+
+    /**
+     * Adds the parameters into context's ParameterMap
+     *
+     * @param ac        The action context
+     * @param newParams The parameter map to apply
+     *                  <p/>
+     *                  In this class this is a no-op, since the parameters were fetched from the same location.
+     *                  In subclasses both retrieveParameters() and addParametersToContext() should be overridden.
+     */
+    protected void addParametersToContext(ActionContext ac, Map<String, Object> newParams) {
+    }
+
+    protected void setParameters(Object action, ValueStack stack, final Map<String, Object> parameters) {
+        ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware)
+                ? (ParameterNameAware) action : null;
+
+        Map<String, Object> params;
+        Map<String, Object> acceptableParameters;
+        if (ordered) {
+            params = new TreeMap<String, Object>(getOrderedComparator());
+            acceptableParameters = new TreeMap<String, Object>(getOrderedComparator());
+            params.putAll(parameters);
+        } else {
+            params = new TreeMap<String, Object>(parameters);
+            acceptableParameters = new TreeMap<String, Object>();
+        }
+
+        for (Map.Entry<String, Object> entry : params.entrySet()) {
+            String name = entry.getKey();
+
+            boolean acceptableName = acceptableName(name)
+                    && (parameterNameAware == null
+                    || parameterNameAware.acceptableParameterName(name));
+
+            if (acceptableName) {
+                acceptableParameters.put(name, entry.getValue());
+            }
+        }
+
+        ValueStack newStack = valueStackFactory.createValueStack(stack);
+        boolean clearableStack = newStack instanceof ClearableValueStack;
+        if (clearableStack) {
+            //if the stack's context can be cleared, do that to prevent OGNL
+            //from having access to objects in the stack, see XW-641
+            ((ClearableValueStack)newStack).clearContextValues();
+            Map<String, Object> context = newStack.getContext();
+            ReflectionContextState.setCreatingNullObjects(context, true);
+            ReflectionContextState.setDenyMethodExecution(context, true);
+            ReflectionContextState.setReportingConversionErrors(context, true);
+
+            //keep locale from original context
+            context.put(ActionContext.LOCALE, stack.getContext().get(ActionContext.LOCALE));
+        }
+
+        boolean memberAccessStack = newStack instanceof MemberAccessValueStack;
+        if (memberAccessStack) {
+            //block or allow access to properties
+            //see WW-2761 for more details
+            MemberAccessValueStack accessValueStack = (MemberAccessValueStack) newStack;
+            accessValueStack.setAcceptProperties(acceptParams);
+            accessValueStack.setExcludeProperties(excludeParams);
+        }
+
+        for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) {
+            String name = entry.getKey();
+            Object value = entry.getValue();
+            try {
+                newStack.setValue(name, value);
+            } catch (RuntimeException e) {
+                if (devMode) {
+                    String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{
+                             "Unexpected Exception caught setting '" + name + "' on '" + action.getClass() + ": " + e.getMessage()
+                    });
+                    LOG.error(developerNotification);
+                    if (action instanceof ValidationAware) {
+                        ((ValidationAware) action).addActionMessage(developerNotification);
+                    }
+                }
+            }
+        }
+
+        if (clearableStack && (stack.getContext() != null) && (newStack.getContext() != null))
+            stack.getContext().put(ActionContext.CONVERSION_ERRORS, newStack.getContext().get(ActionContext.CONVERSION_ERRORS));
+
+        addParametersToContext(ActionContext.getContext(), acceptableParameters);
+    }
+
+    /**
+     * Gets an instance of the comparator to use for the ordered sorting.  Override this
+     * method to customize the ordering of the parameters as they are set to the
+     * action.
+     *
+     * @return A comparator to sort the parameters
+     */
+    protected Comparator<String> getOrderedComparator() {
+        return rbCollator;
+    }
+
+    private String getParameterLogMap(Map<String, Object> parameters) {
+        if (parameters == null) {
+            return "NONE";
+        }
+
+        StringBuilder logEntry = new StringBuilder();
+        for (Map.Entry entry : parameters.entrySet()) {
+            logEntry.append(String.valueOf(entry.getKey()));
+            logEntry.append(" => ");
+            if (entry.getValue() instanceof Object[]) {
+                Object[] valueArray = (Object[]) entry.getValue();
+                logEntry.append("[ ");
+                if (valueArray.length > 0 ) {
+                    for (int indexA = 0; indexA < (valueArray.length - 1); indexA++) {
+                        Object valueAtIndex = valueArray[indexA];
+                        logEntry.append(String.valueOf(valueAtIndex));
+                        logEntry.append(", ");
+                    }
+                    logEntry.append(String.valueOf(valueArray[valueArray.length - 1]));
+                }
+                logEntry.append(" ] ");
+            } else {
+                logEntry.append(String.valueOf(entry.getValue()));
+            }
+        }
+
+        return logEntry.toString();
+    }
+
+    protected boolean acceptableName(String name) {
+        return isAccepted(name) && !isExcluded(name);
+    }
+
+    protected boolean isAccepted(String paramName) {
+        if (!this.acceptParams.isEmpty()) {
+            for (Pattern pattern : acceptParams) {
+                Matcher matcher = pattern.matcher(paramName);
+                if (matcher.matches()) {
+                    return true;
+                }
+            }
+            return false;
+        } else
+            return acceptedPattern.matcher(paramName).matches();
+    }
+
+    protected boolean isExcluded(String paramName) {
+        if (!this.excludeParams.isEmpty()) {
+            for (Pattern pattern : excludeParams) {
+                Matcher matcher = pattern.matcher(paramName);
+                if (matcher.matches()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Whether to order the parameters or not
+     *
+     * @return True to order
+     */
+    public boolean isOrdered() {
+        return ordered;
+    }
+
+    /**
+     * Set whether to order the parameters by object depth or not
+     *
+     * @param ordered True to order them
+     */
+    public void setOrdered(boolean ordered) {
+        this.ordered = ordered;
+    }
+
+    /**
+     * Gets a set of regular expressions of parameters to remove
+     * from the parameter map
+     *
+     * @return A set of compiled regular expression patterns
+     */
+    protected Set getExcludeParamsSet() {
+        return excludeParams;
+    }
+
+    /**
+     * Sets a comma-delimited list of regular expressions to match
+     * parameters that should be removed from the parameter map.
+     *
+     * @param commaDelim A comma-delimited list of regular expressions
+     */
+    public void setExcludeParams(String commaDelim) {
+        Collection<String> excludePatterns = asCollection(commaDelim);
+        if (excludePatterns != null) {
+            excludeParams = new HashSet<Pattern>();
+            for (String pattern : excludePatterns) {
+                excludeParams.add(Pattern.compile(pattern));
+            }
+        }
+    }
+
+    /**
+     * Return a collection from the comma delimited String.
+     *
+     * @param commaDelim the comma delimited String.
+     * @return A collection from the comma delimited String. Returns <tt>null</tt> if the string is empty.
+     */
+    private Collection<String> asCollection(String commaDelim) {
+        if (commaDelim == null || commaDelim.trim().length() == 0) {
+            return null;
+        }
+        return TextParseUtil.commaDelimitedStringToSet(commaDelim);
+    }
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PreResultListener.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PreResultListener.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PreResultListener.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PreResultListener.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2002-2007,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ActionInvocation;
+
+
+/**
+ * PreResultListeners may be registered with an {@link ActionInvocation} to get a callback after the
+ * {@link org.apache.struts2.xwork2.Action} has been executed but before the {@link org.apache.struts2.xwork2.Result}
+ * is executed.
+ *
+ * @author Jason Carreira
+ */
+public interface PreResultListener {
+
+    /**
+     * This callback method will be called after the {@link org.apache.struts2.xwork2.Action} execution and
+     * before the {@link org.apache.struts2.xwork2.Result} execution.
+     *
+     * @param invocation  the action invocation
+     * @param resultCode  the result code returned by the action (eg. <code>success</code>).
+     */
+    void beforeResult(ActionInvocation invocation, String resultCode);
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PrefixMethodInvocationUtil.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PrefixMethodInvocationUtil.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PrefixMethodInvocationUtil.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PrefixMethodInvocationUtil.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * A utility class for invoking prefixed methods in action class.
+ * 
+ * Interceptors that made use of this class are:
+ * <ul>
+ * 	 <li>DefaultWorkflowInterceptor</li>
+ *   <li>PrepareInterceptor</li>
+ * </ul>
+ * 
+ * <p/>
+ * 
+ * <!-- START SNIPPET: javadocDefaultWorkflowInterceptor -->
+ * 
+ * <b>In DefaultWorkflowInterceptor</b>
+ * <p>applies only when action implements {@link org.apache.struts2.xwork2.Validateable}</p>
+ * <ol>
+ *    <li>if the action class have validate{MethodName}(), it will be invoked</li>
+ *    <li>else if the action class have validateDo{MethodName}(), it will be invoked</li>
+ *    <li>no matter if 1] or 2] is performed, if alwaysInvokeValidate property of the interceptor is "true" (which is by default "true"), validate() will be invoked.</li>
+ * </ol>
+ * 
+ * <!-- END SNIPPET: javadocDefaultWorkflowInterceptor -->
+ * 
+ * 
+ * <!-- START SNIPPET: javadocPrepareInterceptor -->
+ * 
+ * <b>In PrepareInterceptor</b>
+ * <p>Applies only when action implements Preparable</p>
+ * <ol>
+ *    <li>if the action class have prepare{MethodName}(), it will be invoked</li>
+ *    <li>else if the action class have prepareDo(MethodName()}(), it will be invoked</li>
+ *    <li>no matter if 1] or 2] is performed, if alwaysinvokePrepare property of the interceptor is "true" (which is by default "true"), prepare() will be invoked.</li>
+ * </ol>
+ * 
+ * <!-- END SNIPPET: javadocPrepareInterceptor -->
+ * 
+ * @author Philip Luppens
+ * @author tm_jee
+ */
+public class PrefixMethodInvocationUtil {
+	
+	private static final Logger LOG = LoggerFactory.getLogger(PrefixMethodInvocationUtil.class);
+
+    private static final String DEFAULT_INVOCATION_METHODNAME = "execute";
+
+    private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
+
+    /**
+	 * This method will prefix <code>actionInvocation</code>'s <code>ActionProxy</code>'s
+	 * <code>method</code> with <code>prefixes</code> before invoking the prefixed method.
+	 * Order of the <code>prefixes</code> is important, as this method will return once 
+	 * a prefixed method is found in the action class.
+	 * 
+	 * <p/>
+	 * 
+	 * For example, with
+	 * <pre>
+	 *   invokePrefixMethod(actionInvocation, new String[] { "prepare", "prepareDo" });
+	 * </pre>
+	 * 
+	 * Assuming <code>actionInvocation.getProxy(),getMethod()</code> returns "submit", 
+	 * the order of invocation would be as follows:-
+	 * <ol>
+	 *   <li>prepareSubmit()</li>
+	 *   <li>prepareDoSubmit()</li>
+	 * </ol>
+	 * 
+	 * If <code>prepareSubmit()</code> exists, it will be invoked and this method 
+	 * will return, <code>prepareDoSubmit()</code> will NOT be invoked. 
+	 * 
+	 * <p/>
+	 * 
+	 * On the other hand, if <code>prepareDoSubmit()</code> does not exists, and 
+	 * <code>prepareDoSubmit()</code> exists, it will be invoked.
+	 * 
+	 * <p/>
+	 * 
+	 * If none of those two methods exists, nothing will be invoked.
+	 * 
+	 * @param actionInvocation  the action invocation
+	 * @param prefixes  prefixes for method names
+	 * @throws InvocationTargetException is thrown if invocation of a method failed.
+	 * @throws IllegalAccessException  is thrown if invocation of a method failed.
+	 */
+	public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
+		Object action = actionInvocation.getAction();
+		
+		String methodName = actionInvocation.getProxy().getMethod();
+		
+		if (methodName == null) {
+			// if null returns (possible according to the docs), use the default execute 
+	        methodName = DEFAULT_INVOCATION_METHODNAME;
+		}
+		
+		Method method = getPrefixedMethod(prefixes, methodName, action);
+		if (method != null) {
+			method.invoke(action, new Object[0]);
+		}
+	}
+	
+	
+	/**
+	 * This method returns a {@link Method} in <code>action</code>. The method 
+	 * returned is found by searching for method in <code>action</code> whose method name
+	 * is equals to the result of appending each <code>prefixes</code>
+	 * to <code>methodName</code>. Only the first method found will be returned, hence
+	 * the order of <code>prefixes</code> is important. If none is found this method
+	 * will return null.
+	 * 
+	 * @param prefixes the prefixes to prefix the <code>methodName</code>
+	 * @param methodName the method name to be prefixed with <code>prefixes</code>
+	 * @param action the action class of which the prefixed method is to be search for.
+	 * @return a {@link Method} if one is found, else <tt>null</tt>.
+	 */
+	public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {
+		assert(prefixes != null);
+		String capitalizedMethodName = capitalizeMethodName(methodName);
+        for (String prefixe : prefixes) {
+            String prefixedMethodName = prefixe + capitalizedMethodName;
+            try {
+                return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY);
+            }
+            catch (NoSuchMethodException e) {
+                // hmm -- OK, try next prefix
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("cannot find method [" + prefixedMethodName + "] in action [" + action + "]");
+                }
+            }
+        }
+		return null;
+	}
+	
+	/**
+	 * This method capitalized the first character of <code>methodName</code>.
+	 * <br/>
+	 * eg. <code>capitalizeMethodName("someMethod");</code> will return <code>"SomeMethod"</code>.
+	 * 
+	 * @param methodName the method name
+	 * @return capitalized method name
+	 */
+	public static String capitalizeMethodName(String methodName) {
+		assert(methodName != null);
+		return methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
+	}
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PrepareInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PrepareInterceptor.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PrepareInterceptor.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/PrepareInterceptor.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,172 @@
+/*
+ * $Id: PrepareInterceptor.java 1209415 2011-12-02 11:24:48Z lukaszlenart $
+ * Copyright 2002-2007,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.Preparable;
+
+import java.lang.reflect.InvocationTargetException;
+
+
+/**
+ * <!-- START SNIPPET: description -->
+ *
+ * This interceptor calls <code>prepare()</code> on actions which implement
+ * {@link org.apache.struts2.xwork2.Preparable}. This interceptor is very useful for any situation where
+ * you need to ensure some logic runs before the actual execute method runs.
+ *
+ * <p/> A typical use of this is to run some logic to load an object from the
+ * database so that when parameters are set they can be set on this object. For
+ * example, suppose you have a User object with two properties: <i>id</i> and
+ * <i>name</i>. Provided that the params interceptor is called twice (once
+ * before and once after this interceptor), you can load the User object using
+ * the id property, and then when the second params interceptor is called the
+ * parameter <i>user.name</i> will be set, as desired, on the actual object
+ * loaded from the database. See the example for more info.
+ *
+ * <p/>
+ * <b>Note:</b> Since XWork 2.0.2, this interceptor extends {@link MethodFilterInterceptor}, therefore being
+ * able to deal with excludeMethods / includeMethods parameters. See [Workflow Interceptor]
+ * (class {@link DefaultWorkflowInterceptor}) for documentation and examples on how to use this feature.
+ *
+ * <p/><b>Update</b>: Added logic to execute a prepare{MethodName} and conditionally
+ * the a general prepare() Method, depending on the 'alwaysInvokePrepare' parameter/property
+ * which is by default true. This allows us to run some logic based on the method
+ * name we specify in the {@link org.apache.struts2.xwork2.ActionProxy}. For example, you can specify a
+ * prepareInput() method that will be run before the invocation of the input method.
+ *
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Interceptor parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ *
+ * <ul>
+ *
+ * <li>alwaysInvokePrepare - Default to true. If true, prepare will always be invoked,
+ * otherwise it will not.</li>
+ *
+ * </ul>
+ *
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Extending the interceptor:</u>
+ *
+ * <p/>
+ *
+ * <!-- START SNIPPET: extending -->
+ *
+ * There are no known extension points to this interceptor.
+ *
+ * <!-- END SNIPPET: extending -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &lt;!-- Calls the params interceptor twice, allowing you to
+ *       pre-load data for the second time parameters are set --&gt;
+ *  &lt;action name="someAction" class="com.examples.SomeAction"&gt;
+ *      &lt;interceptor-ref name="params"/&gt;
+ *      &lt;interceptor-ref name="prepare"/&gt;
+ *      &lt;interceptor-ref name="basicStack"/&gt;
+ *      &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
+ *  &lt;/action&gt;
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author Jason Carreira
+ * @author Philip Luppens
+ * @author tm_jee
+ * @see org.apache.struts2.xwork2.Preparable
+ */
+public class PrepareInterceptor extends MethodFilterInterceptor {
+
+    private static final long serialVersionUID = -5216969014510719786L;
+
+    private final static String PREPARE_PREFIX = "prepare";
+    private final static String ALT_PREPARE_PREFIX = "prepareDo";
+
+    private boolean alwaysInvokePrepare = true;
+    private boolean firstCallPrepareDo = false;
+
+    /**
+     * Sets if the <code>preapare</code> method should always be executed.
+     * <p/>
+     * Default is <tt>true</tt>.
+     *
+     * @param alwaysInvokePrepare if <code>prepare</code> should always be executed or not.
+     */
+    public void setAlwaysInvokePrepare(String alwaysInvokePrepare) {
+        this.alwaysInvokePrepare = Boolean.parseBoolean(alwaysInvokePrepare);
+    }
+
+    /**
+     * Sets if the <code>prepareDoXXX</code> method should be called first
+     * <p/>
+     * Default is <tt>false</tt> for backward compatibility
+     *
+     * @param firstCallPrepareDo if <code>prepareDoXXX</code> should be called first
+     */
+    public void setFirstCallPrepareDo(String firstCallPrepareDo) {
+        this.firstCallPrepareDo = Boolean.parseBoolean(firstCallPrepareDo);
+    }
+
+    @Override
+    public String doIntercept(ActionInvocation invocation) throws Exception {
+        Object action = invocation.getAction();
+
+        if (action instanceof Preparable) {
+            try {
+                String[] prefixes;
+                if (firstCallPrepareDo) {
+                    prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
+                } else {
+                    prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
+                }
+                PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
+            }
+            catch (InvocationTargetException e) {
+                /*
+                 * The invoked method threw an exception and reflection wrapped it
+                 * in an InvocationTargetException.
+                 * If possible re-throw the original exception so that normal
+                 * exception handling will take place.
+                 */
+                Throwable cause = e.getCause();
+                if (cause instanceof Exception) {
+                    throw (Exception) cause;
+                } else if(cause instanceof Error) {
+                    throw (Error) cause;
+                } else {
+                    /*
+                     * The cause is not an Exception or Error (must be Throwable) so
+                     * just re-throw the wrapped exception.
+                     */
+                    throw e;
+                }
+            }
+
+            if (alwaysInvokePrepare) {
+                ((Preparable) action).prepare();
+            }
+        }
+
+        return invocation.invoke();
+    }
+
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ScopedModelDriven.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ScopedModelDriven.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ScopedModelDriven.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ScopedModelDriven.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ModelDriven;
+
+/**
+ * Adds the ability to set a model, probably retrieved from a given state.
+ */
+public interface ScopedModelDriven<T> extends ModelDriven<T> {
+
+    /**
+     * Sets the model
+     */
+    void setModel(T model);
+    
+    /**
+     * Sets the key under which the model is stored
+     * @param key The model key
+     */
+    void setScopeKey(String key);
+    
+    /**
+     * Gets the key under which the model is stored
+     */
+    String getScopeKey();
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ScopedModelDrivenInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ScopedModelDrivenInterceptor.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ScopedModelDrivenInterceptor.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/ScopedModelDrivenInterceptor.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.ObjectFactory;
+import org.apache.struts2.xwork2.XWorkException;
+import org.apache.struts2.xwork2.config.entities.ActionConfig;
+import org.apache.struts2.xwork2.inject.Inject;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * <!-- START SNIPPET: description -->
+ *
+ * An interceptor that enables scoped model-driven actions.
+ *
+ * <p/>This interceptor only activates on actions that implement the {@link ScopedModelDriven} interface.  If
+ * detected, it will retrieve the model class from the configured scope, then provide it to the Action.
+ *  
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Interceptor parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ *
+ * <ul>
+ *
+ * <li>className - The model class name.  Defaults to the class name of the object returned by the getModel() method.</li>
+ *            
+ * <li>name - The key to use when storing or retrieving the instance in a scope.  Defaults to the model
+ *            class name.</li>
+ *
+ * <li>scope - The scope to store and retrieve the model.  Defaults to 'request' but can also be 'session'.</li>
+ * </ul>
+ *
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Extending the interceptor:</u>
+ *
+ * <p/>
+ *
+ * <!-- START SNIPPET: extending -->
+ *
+ * There are no known extension points for this interceptor.
+ *
+ * <!-- END SNIPPET: extending -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * 
+ * &lt;-- Basic usage --&gt;
+ * &lt;interceptor name="scopedModelDriven" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor" /&gt;
+ * 
+ * &lt;-- Using all available parameters --&gt;
+ * &lt;interceptor name="gangsterForm" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor"&gt;
+ *      &lt;param name="scope"&gt;session&lt;/param&gt;
+ *      &lt;param name="name"&gt;gangsterForm&lt;/param&gt;
+ *      &lt;param name="className"&gt;com.opensymphony.example.GangsterForm&lt;/param&gt;
+ *  &lt;/interceptor&gt;
+ * 
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ */
+public class ScopedModelDrivenInterceptor extends AbstractInterceptor {
+
+    private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
+    
+    private static final String GET_MODEL = "getModel";
+    private String scope;
+    private String name;
+    private String className;
+    private ObjectFactory objectFactory;
+    
+    @Inject
+    public void setObjectFactory(ObjectFactory factory) {
+        this.objectFactory = factory;
+    }
+    
+    protected Object resolveModel(ObjectFactory factory, ActionContext actionContext, String modelClassName, String modelScope, String modelName) throws Exception {
+        Object model = null;
+        Map<String, Object> scopeMap = actionContext.getContextMap();
+        if ("session".equals(modelScope)) {
+            scopeMap = actionContext.getSession();
+        }
+        
+        model = scopeMap.get(modelName);
+        if (model == null) {
+            model = factory.buildBean(modelClassName, null);
+            scopeMap.put(modelName, model);
+        }
+        return model;
+    }
+
+    @Override
+    public String intercept(ActionInvocation invocation) throws Exception {
+        Object action = invocation.getAction();
+
+        if (action instanceof ScopedModelDriven) {
+            ScopedModelDriven modelDriven = (ScopedModelDriven) action;
+            if (modelDriven.getModel() == null) {
+                ActionContext ctx = ActionContext.getContext();
+                ActionConfig config = invocation.getProxy().getConfig();
+                
+                String cName = className;
+                if (cName == null) {
+                    try {
+                        Method method = action.getClass().getMethod(GET_MODEL, EMPTY_CLASS_ARRAY);
+                        Class cls = method.getReturnType();
+                        cName = cls.getName();
+                    } catch (NoSuchMethodException e) {
+                        throw new XWorkException("The " + GET_MODEL + "() is not defined in action " + action.getClass() + "", config);
+                    }
+                }
+                String modelName = name;
+                if (modelName == null) {
+                    modelName = cName;
+                }
+                Object model = resolveModel(objectFactory, ctx, cName, scope, modelName);
+                modelDriven.setModel(model);
+                modelDriven.setScopeKey(modelName);
+            }
+        }
+        return invocation.invoke();
+    }
+
+    /**
+     * @param className the className to set
+     */
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @param scope the scope to set
+     */
+    public void setScope(String scope) {
+        this.scope = scope;
+    }    
+}

Added: struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/StaticParametersInterceptor.java
URL: http://svn.apache.org/viewvc/struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/StaticParametersInterceptor.java?rev=1209569&view=auto
==============================================================================
--- struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/StaticParametersInterceptor.java (added)
+++ struts/struts2/branches/STRUTS_3_X/xwork-core/src/main/java/org/apache/struts2/xwork2/interceptor/StaticParametersInterceptor.java Fri Dec  2 16:33:03 2011
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.xwork2.interceptor;
+
+import org.apache.struts2.xwork2.ActionContext;
+import org.apache.struts2.xwork2.ActionInvocation;
+import org.apache.struts2.xwork2.ValidationAware;
+import org.apache.struts2.xwork2.inject.Inject;
+import org.apache.struts2.xwork2.config.entities.ActionConfig;
+import org.apache.struts2.xwork2.config.entities.Parameterizable;
+import org.apache.struts2.xwork2.util.ClearableValueStack;
+import org.apache.struts2.xwork2.util.LocalizedTextUtil;
+import org.apache.struts2.xwork2.util.reflection.ReflectionContextState;
+import org.apache.struts2.xwork2.util.logging.Logger;
+import org.apache.struts2.xwork2.util.logging.LoggerFactory;
+import org.apache.struts2.xwork2.util.TextParseUtil;
+import org.apache.struts2.xwork2.util.ValueStack;
+import org.apache.struts2.xwork2.util.ValueStackFactory;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+
+/**
+ * <!-- START SNIPPET: description -->
+ *
+ * This interceptor populates the action with the static parameters defined in the action configuration. If the action
+ * implements {@link org.apache.struts2.xwork2.config.entities.Parameterizable}, a map of the static parameters will be also be passed directly to the action.
+ * The static params will be added to the request params map, unless "merge" is set to false.
+ *
+ * <p/> Parameters are typically defined with &lt;param&gt; elements within xwork.xml.
+ *
+ * <!-- END SNIPPET: description -->
+ *
+ * <p/> <u>Interceptor parameters:</u>
+ *
+ * <!-- START SNIPPET: parameters -->
+ *
+ * <ul>
+ *
+ * <li>None</li>
+ *
+ * </ul>
+ *
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <p/> <u>Extending the interceptor:</u>
+ *
+ * <!-- START SNIPPET: extending -->
+ *
+ * <p/>There are no extension points to this interceptor.
+ *
+ * <!-- END SNIPPET: extending -->
+ *
+ * <p/> <u>Example code:</u>
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * &lt;action name="someAction" class="com.examples.SomeAction"&gt;
+ *     &lt;interceptor-ref name="staticParams"&gt;
+ *          &lt;param name="parse"&gt;true&lt;/param&gt;
+ *          &lt;param name="overwrite"&gt;false&lt;/param&gt;
+ *     &lt;/interceptor-ref&gt;
+ *     &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
+ * &lt;/action&gt;
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author Patrick Lightbody
+ */
+public class StaticParametersInterceptor extends AbstractInterceptor {
+
+    private boolean parse;
+    private boolean overwrite;
+    private boolean merge = true;
+
+    static boolean devMode = false;
+
+    private static final Logger LOG = LoggerFactory.getLogger(StaticParametersInterceptor.class);
+
+    private ValueStackFactory valueStackFactory;
+
+    @Inject
+    public void setValueStackFactory(ValueStackFactory valueStackFactory) {
+        this.valueStackFactory = valueStackFactory;
+    }
+
+    @Inject("devMode")
+    public static void setDevMode(String mode) {
+        devMode = "true".equals(mode);
+    }    
+
+    public void setParse(String value) {
+        this.parse = Boolean.valueOf(value).booleanValue();
+    }
+
+     public void setMerge(String value) {
+        this.merge = Boolean.valueOf(value).booleanValue();
+    }
+
+    /**
+     * Overwrites already existing parameters from other sources.
+     * Static parameters are the successor over previously set parameters, if true.
+     *
+     * @param value
+     */
+    public void setOverwrite(String value) {
+        this.overwrite = Boolean.valueOf(value).booleanValue();
+    }
+
+    @Override
+    public String intercept(ActionInvocation invocation) throws Exception {
+        ActionConfig config = invocation.getProxy().getConfig();
+        Object action = invocation.getAction();
+
+        final Map<String, String> parameters = config.getParams();
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Setting static parameters " + parameters);
+        }
+
+        // for actions marked as Parameterizable, pass the static parameters directly
+        if (action instanceof Parameterizable) {
+            ((Parameterizable) action).setParams(parameters);
+        }
+
+        if (parameters != null) {
+            ActionContext ac = ActionContext.getContext();
+            Map<String, Object> contextMap = ac.getContextMap();
+            try {
+                ReflectionContextState.setCreatingNullObjects(contextMap, true);
+                ReflectionContextState.setReportingConversionErrors(contextMap, true);
+                final ValueStack stack = ac.getValueStack();
+
+                ValueStack newStack = valueStackFactory.createValueStack(stack);
+                boolean clearableStack = newStack instanceof ClearableValueStack;
+                if (clearableStack) {
+                    //if the stack's context can be cleared, do that to prevent OGNL
+                    //from having access to objects in the stack, see XW-641
+                    ((ClearableValueStack)newStack).clearContextValues();
+                    Map<String, Object> context = newStack.getContext();
+                    ReflectionContextState.setCreatingNullObjects(context, true);
+                    ReflectionContextState.setDenyMethodExecution(context, true);
+                    ReflectionContextState.setReportingConversionErrors(context, true);
+
+                    //keep locale from original context
+                    context.put(ActionContext.LOCALE, stack.getContext().get(ActionContext.LOCALE));
+                }
+
+                for (Map.Entry<String, String> entry : parameters.entrySet()) {
+                    Object val = entry.getValue();
+                    if (parse && val instanceof String) {
+                        val = TextParseUtil.translateVariables(val.toString(), stack);
+                    }
+                    try {
+                        newStack.setValue(entry.getKey(), val);
+                    } catch (RuntimeException e) {
+                        if (devMode) {
+                            String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{
+                                    "Unexpected Exception caught setting '" + entry.getKey() + "' on '" + action.getClass() + ": " + e.getMessage()
+                            });
+                            LOG.error(developerNotification);
+                            if (action instanceof ValidationAware) {
+                                ((ValidationAware) action).addActionMessage(developerNotification);
+                            }
+                        }
+                    }
+                }
+
+                 if (clearableStack && (stack.getContext() != null) && (newStack.getContext() != null))
+                    stack.getContext().put(ActionContext.CONVERSION_ERRORS, newStack.getContext().get(ActionContext.CONVERSION_ERRORS));
+
+                if (merge)
+                    addParametersToContext(ac, parameters);
+            } finally {
+                ReflectionContextState.setCreatingNullObjects(contextMap, false);
+                ReflectionContextState.setReportingConversionErrors(contextMap, false);
+            }
+        }
+        return invocation.invoke();
+    }
+
+
+    /**
+     * @param ac The action context
+     * @return the parameters from the action mapping in the context.  If none found, returns
+     *         an empty map.
+     */
+    protected Map<String, String> retrieveParameters(ActionContext ac) {
+        ActionConfig config = ac.getActionInvocation().getProxy().getConfig();
+        if (config != null) {
+            return config.getParams();
+        } else {
+            return Collections.emptyMap();
+        }
+    }
+
+    /**
+     * Adds the parameters into context's ParameterMap.
+     * As default, static parameters will not overwrite existing paramaters from other sources.
+     * If you want the static parameters as successor over already existing parameters, set overwrite to <tt>true</tt>.
+     *
+     * @param ac        The action context
+     * @param newParams The parameter map to apply
+     */
+    protected void addParametersToContext(ActionContext ac, Map<String, ?> newParams) {
+        Map<String, Object> previousParams = ac.getParameters();
+
+        Map<String, Object> combinedParams;
+        if ( overwrite ) {
+            if (previousParams != null) {
+                combinedParams = new TreeMap<String, Object>(previousParams);
+            } else {
+                combinedParams = new TreeMap<String, Object>();
+            }
+            if ( newParams != null) {
+                combinedParams.putAll(newParams);
+            }
+        } else {
+            if (newParams != null) {
+                combinedParams = new TreeMap<String, Object>(newParams);
+            } else {
+                combinedParams = new TreeMap<String, Object>();
+            }
+            if ( previousParams != null) {
+                combinedParams.putAll(previousParams);
+            }
+        }
+        ac.setParameters(combinedParams);
+    }
+}