You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by ma...@apache.org on 2009/12/27 19:01:09 UTC
svn commit: r894087 [12/46] - in /struts/xwork/trunk: ./ assembly/
assembly/src/ assembly/src/main/ assembly/src/main/assembly/
assembly/src/main/resources/ core/ core/src/ core/src/main/
core/src/main/java/ core/src/main/java/com/ core/src/main/java/c...
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2002-2007 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+
+/**
+ * <!-- START SNIPPET: description -->
+ * This interceptor logs the start and end of the execution an action (in English-only, not internationalized).
+ * <br/>
+ * <b>Note:</b>: This interceptor will log at <tt>INFO</tt> level.
+ * <p/>
+ * <!-- END SNIPPET: description -->
+ *
+ * <!-- START SNIPPET: parameters -->
+ * There are no parameters for this interceptor.
+ * <!-- END SNIPPET: parameters -->
+ *
+ * <!-- START SNIPPET: extending -->
+ * There are no obvious extensions to the existing interceptor.
+ * <!-- END SNIPPET: extending -->
+ *
+ * <pre>
+ * <!-- START SNIPPET: example -->
+ * <!-- prints out a message before and after the immediate action execution -->
+ * <action name="someAction" class="com.examples.SomeAction">
+ * <interceptor-ref name="completeStack"/>
+ * <interceptor-ref name="logger"/>
+ * <result name="success">good_result.ftl</result>
+ * </action>
+ *
+ * <!-- prints out a message before any more interceptors continue and after they have finished -->
+ * <action name="someAction" class="com.examples.SomeAction">
+ * <interceptor-ref name="logger"/>
+ * <interceptor-ref name="completeStack"/>
+ * <result name="success">good_result.ftl</result>
+ * </action>
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author Jason Carreira
+ */
+public class LoggingInterceptor extends AbstractInterceptor {
+ private static final Logger LOG = LoggerFactory.getLogger(LoggingInterceptor.class);
+ private static final String FINISH_MESSAGE = "Finishing execution stack for action ";
+ private static final String START_MESSAGE = "Starting execution stack for action ";
+
+ @Override
+ public String intercept(ActionInvocation invocation) throws Exception {
+ logMessage(invocation, START_MESSAGE);
+ String result = invocation.invoke();
+ logMessage(invocation, FINISH_MESSAGE);
+ return result;
+ }
+
+ private void logMessage(ActionInvocation invocation, String baseMessage) {
+ if (LOG.isInfoEnabled()) {
+ StringBuilder message = new StringBuilder(baseMessage);
+ String namespace = invocation.getProxy().getNamespace();
+
+ if ((namespace != null) && (namespace.trim().length() > 0)) {
+ message.append(namespace).append("/");
+ }
+
+ message.append(invocation.getProxy().getActionName());
+ LOG.info(message.toString());
+ }
+ }
+
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/LoggingInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.util.TextParseUtil;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Set;
+
+
+/**
+ * <!-- START SNIPPET: javadoc -->
+ *
+ * MethodFilterInterceptor is an abstract <code>Interceptor</code> used as
+ * a base class for interceptors that will filter execution based on method
+ * names according to specified included/excluded method lists.
+ *
+ * <p/>
+ *
+ * Settable parameters are as follows:
+ *
+ * <ul>
+ * <li>excludeMethods - method names to be excluded from interceptor processing</li>
+ * <li>includeMethods - method names to be included in interceptor processing</li>
+ * </ul>
+ *
+ * <p/>
+ *
+ * <b>NOTE:</b> If method name are available in both includeMethods and
+ * excludeMethods, it will be considered as an included method:
+ * includeMethods takes precedence over excludeMethods.
+ *
+ * <p/>
+ *
+ * Interceptors that extends this capability include:
+ *
+ * <ul>
+ * <li>TokenInterceptor</li>
+ * <li>TokenSessionStoreInterceptor</li>
+ * <li>DefaultWorkflowInterceptor</li>
+ * <li>ValidationInterceptor</li>
+ * </ul>
+ *
+ * <!-- END SNIPPET: javadoc -->
+ *
+ * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
+ * @author Rainer Hermanns
+ *
+ * @see org.apache.struts2.interceptor.TokenInterceptor
+ * @see org.apache.struts2.interceptor.TokenSessionStoreInterceptor
+ * @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
+ * @see com.opensymphony.xwork2.validator.ValidationInterceptor
+ *
+ * @version $Date$ $Id$
+ */
+public abstract class MethodFilterInterceptor extends AbstractInterceptor {
+ protected transient Logger log = LoggerFactory.getLogger(getClass());
+
+ protected Set<String> excludeMethods = Collections.emptySet();
+ protected Set<String> includeMethods = Collections.emptySet();
+
+ public void setExcludeMethods(String excludeMethods) {
+ this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods);
+ }
+
+ public Set<String> getExcludeMethodsSet() {
+ return excludeMethods;
+ }
+
+ public void setIncludeMethods(String includeMethods) {
+ this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods);
+ }
+
+ public Set<String> getIncludeMethodsSet() {
+ return includeMethods;
+ }
+
+ @Override
+ public String intercept(ActionInvocation invocation) throws Exception {
+ if (applyInterceptor(invocation)) {
+ return doIntercept(invocation);
+ }
+ return invocation.invoke();
+ }
+
+ protected boolean applyInterceptor(ActionInvocation invocation) {
+ String method = invocation.getProxy().getMethod();
+ // ValidationInterceptor
+ boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, method);
+ if (log.isDebugEnabled()) {
+ if (!applyMethod) {
+ log.debug("Skipping Interceptor... Method [" + method + "] found in exclude list.");
+ }
+ }
+ return applyMethod;
+ }
+
+ /**
+ * Subclasses must override to implement the interceptor logic.
+ *
+ * @param invocation the action invocation
+ * @return the result of invocation
+ * @throws Exception
+ */
+ protected abstract String doIntercept(ActionInvocation invocation) throws Exception;
+
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2002-2007 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.util.TextParseUtil;
+import com.opensymphony.xwork2.util.WildcardHelper;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Utility class contains common methods used by
+ * {@link com.opensymphony.xwork2.interceptor.MethodFilterInterceptor}.
+ *
+ * @author tm_jee
+ */
+public class MethodFilterInterceptorUtil {
+
+ /**
+ * Static method to decide if the specified <code>method</code> should be
+ * apply (not filtered) depending on the set of <code>excludeMethods</code> and
+ * <code>includeMethods</code>.
+ *
+ * <ul>
+ * <li>
+ * <code>includeMethods</code> takes precedence over <code>excludeMethods</code>
+ * </li>
+ * </ul>
+ * <b>Note:</b> Supports wildcard listings in includeMethods/excludeMethods
+ *
+ * @param excludeMethods list of methods to exclude.
+ * @param includeMethods list of methods to include.
+ * @param method the specified method to check
+ * @return <tt>true</tt> if the method should be applied.
+ */
+ public static boolean applyMethod(Set<String> excludeMethods, Set<String> includeMethods, String method) {
+
+ // quick check to see if any actual pattern matching is needed
+ boolean needsPatternMatch = false;
+ Iterator quickIter = includeMethods.iterator();
+ for (String incMeth : includeMethods) {
+ if (!"*".equals(incMeth) && incMeth.contains("*")) {
+ needsPatternMatch = true;
+ }
+ }
+
+ for (String incMeth : excludeMethods) {
+ if (!"*".equals(incMeth) && incMeth.contains("*")) {
+ needsPatternMatch = true;
+ }
+ }
+
+ // this section will try to honor the original logic, while
+ // still allowing for wildcards later
+ if (!needsPatternMatch && (includeMethods.contains("*") || includeMethods.size() == 0) ) {
+ if (excludeMethods != null
+ && excludeMethods.contains(method)
+ && !includeMethods.contains(method) ) {
+ return false;
+ }
+ }
+
+ // test the methods using pattern matching
+ WildcardHelper wildcard = new WildcardHelper();
+ String methodCopy ;
+ if (method == null ) { // no method specified
+ methodCopy = "";
+ }
+ else {
+ methodCopy = new String(method);
+ }
+ for (String pattern : includeMethods) {
+ if (pattern.contains("*")) {
+ int[] compiledPattern = wildcard.compilePattern(pattern);
+ HashMap<String,String> matchedPatterns = new HashMap<String, String>();
+ boolean matches = wildcard.match(matchedPatterns, methodCopy, compiledPattern);
+ if (matches) {
+ return true; // run it, includeMethods takes precedence
+ }
+ }
+ else {
+ if (pattern.equals(methodCopy)) {
+ return true; // run it, includeMethods takes precedence
+ }
+ }
+ }
+ if (excludeMethods.contains("*") ) {
+ return false;
+ }
+
+ // CHECK ME: Previous implementation used include method
+ for ( String pattern : excludeMethods) {
+ if (pattern.contains("*")) {
+ int[] compiledPattern = wildcard.compilePattern(pattern);
+ HashMap<String,String> matchedPatterns = new HashMap<String, String>();
+ boolean matches = wildcard.match(matchedPatterns, methodCopy, compiledPattern);
+ if (matches) {
+ // if found, and wasn't included earlier, don't run it
+ return false;
+ }
+ }
+ else {
+ if (pattern.equals(methodCopy)) {
+ // if found, and wasn't included earlier, don't run it
+ return false;
+ }
+ }
+ }
+
+
+ // default fall-back from before changes
+ return includeMethods.size() == 0 || includeMethods.contains(method) || includeMethods.contains("*");
+ }
+
+ /**
+ * Same as {@link #applyMethod(Set, Set, String)}, except that <code>excludeMethods</code>
+ * and <code>includeMethods</code> are supplied as comma separated string.
+ *
+ * @param excludeMethods comma seperated string of methods to exclude.
+ * @param includeMethods comma seperated string of methods to include.
+ * @param method the specified method to check
+ * @return <tt>true</tt> if the method should be applied.
+ */
+ public static boolean applyMethod(String excludeMethods, String includeMethods, String method) {
+ Set<String> includeMethodsSet = TextParseUtil.commaDelimitedStringToSet(includeMethods == null? "" : includeMethods);
+ Set<String> excludeMethodsSet = TextParseUtil.commaDelimitedStringToSet(excludeMethods == null? "" : excludeMethods);
+
+ return applyMethod(excludeMethodsSet, includeMethodsSet, method);
+ }
+
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/MethodFilterInterceptorUtil.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ModelDriven;
+import com.opensymphony.xwork2.util.CompoundRoot;
+import com.opensymphony.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 -->
+ * <action name="someAction" class="com.examples.SomeAction">
+ * <interceptor-ref name="modelDriven"/>
+ * <interceptor-ref name="basicStack"/>
+ * <result name="success">good_result.ftl</result>
+ * </action>
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author tm_jee
+ * @version $Date$ $Id$
+ */
+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);
+ }
+ }
+ }
+ }
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ModelDrivenInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/NoParameters.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/NoParameters.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/NoParameters.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/NoParameters.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2002-2007 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.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 {
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/NoParameters.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/NoParameters.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterFilterInterceptor.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterFilterInterceptor.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterFilterInterceptor.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterFilterInterceptor.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2002-2007 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.util.TextParseUtil;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.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 -->
+ * <interceptors>
+ * ...
+ * <interceptor name="parameterFilter" class="com.opensymphony.xwork2.interceptor.ParameterFilterInterceptor"/>
+ * ...
+ * </interceptors>
+ *
+ * <action ....>
+ * ...
+ * <interceptor-ref name="parameterFilter">
+ * <param name="blocked">person,person.address.createDate,personDao</param>
+ * </interceptor-ref>
+ * ...
+ * </action>
+ * <!-- 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 (Object o : parameters.keySet()) {
+ String param = o.toString();
+
+ boolean currentAllowed = !isDefaultBlock();
+
+ boolean foundApplicableRule = false;
+ for (Object o1 : includesExcludesMap.keySet()) {
+ String currRule = (String) o1;
+
+ if (param.startsWith(currRule)
+ && (param.length() == currRule.length()
+ || isPropSeperator(param.charAt(currRule.length())))) {
+ currentAllowed = includesExcludesMap.get(currRule).booleanValue();
+ } else {
+ if (foundApplicableRule) {
+ foundApplicableRule = false;
+ break;
+ }
+ }
+ }
+ 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);
+ }
+
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterFilterInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterFilterInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterNameAware.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterNameAware.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterNameAware.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterNameAware.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2002-2007 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.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);
+
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterNameAware.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterNameAware.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2002-2007 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.util.TextParseUtil;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.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 -->
+ *
+ * <action name="sample" class="org.martingilday.Sample">
+ * <interceptor-ref name="paramRemover">
+ * <param name="paramNames">aParam,anotherParam</param>
+ * <param name="paramValues">--,-1</param>
+ * </interceptor-ref>
+ * <interceptor-ref name="defaultStack" />
+ * ...
+ * </action>
+ *
+ * <!-- 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 com.opensymphony.xwork2.interceptor.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);
+ }
+}
+
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParameterRemoverInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2002-2007 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+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;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ValidationAware;
+import com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler;
+import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.ClearableValueStack;
+import com.opensymphony.xwork2.util.LocalizedTextUtil;
+import com.opensymphony.xwork2.util.MemberAccessValueStack;
+import com.opensymphony.xwork2.util.TextParseUtil;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
+
+
+/**
+ * <!-- 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 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 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 InstantiatingNullHandler} javadocs for more information.
+ * <p/>
+ * <p/> Finally, a third flag ({@link XWorkConverter#REPORT_CONVERSION_ERRORS}) is set that indicates any errors when
+ * converting the the values to their final data type (String[] -> 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 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 -->
+ * <action name="someAction" class="com.examples.SomeAction">
+ * <interceptor-ref name="params"/>
+ * <result name="success">good_result.ftl</result>
+ * </action>
+ * <!-- 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;
+
+ private String acceptedParamNames = "[[\\p{Graph}\\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));
+ }
+ }
+ }
+
+ /**
+ * Compares based on number of '.' characters (fewer is higher)
+ */
+ static final Comparator<String> rbCollator = new Comparator<String>() {
+ public int compare(String s1, String s2) {
+ int l1 = 0, l2 = 0;
+ for (int i = s1.length() - 1; i >= 0; i--) {
+ if (s1.charAt(i) == '.') l1++;
+ }
+ for (int i = s2.length() - 1; i >= 0; i--) {
+ if (s2.charAt(i) == '.') l2++;
+ }
+ 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) {
+ if (isAccepted(name) && !isExcluded(name)) {
+ return true;
+ }
+ return false;
+ }
+
+ 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);
+ }
+
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2002-2007 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.ActionInvocation;
+
+
+/**
+ * PreResultListeners may be registered with an {@link ActionInvocation} to get a callback after the
+ * {@link com.opensymphony.xwork2.Action} has been executed but before the {@link com.opensymphony.xwork2.Result}
+ * is executed.
+ *
+ * @author Jason Carreira
+ */
+public interface PreResultListener {
+
+ /**
+ * This callback method will be called after the {@link com.opensymphony.xwork2.Action} execution and
+ * before the {@link com.opensymphony.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);
+
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PreResultListener.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.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 com.opensymphony.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);
+ }
+
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrefixMethodInvocationUtil.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2002-2007 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.Preparable;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+
+
+/**
+ * <!-- START SNIPPET: description -->
+ *
+ * This interceptor calls <code>prepare()</code> on actions which implement
+ * {@link 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 com.opensymphony.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 -->
+ * <!-- Calls the params interceptor twice, allowing you to
+ * pre-load data for the second time parameters are set -->
+ * <action name="someAction" class="com.examples.SomeAction">
+ * <interceptor-ref name="params"/>
+ * <interceptor-ref name="prepare"/>
+ * <interceptor-ref name="basicStack"/>
+ * <result name="success">good_result.ftl</result>
+ * </action>
+ * <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * @author Jason Carreira
+ * @author Philip Luppens
+ * @author tm_jee
+ * @see com.opensymphony.xwork2.Preparable
+ */
+public class PrepareInterceptor extends MethodFilterInterceptor {
+
+ private static final long serialVersionUID = -5216969014510719786L;
+
+ private static final Logger LOG = LoggerFactory.getLogger(PrepareInterceptor.class);
+
+ private final static String PREPARE_PREFIX = "prepare";
+ private final static String ALT_PREPARE_PREFIX = "prepareDo";
+
+ private boolean alwaysInvokePrepare = true;
+
+ /**
+ * 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);
+ }
+
+ @Override
+ public String doIntercept(ActionInvocation invocation) throws Exception {
+ Object action = invocation.getAction();
+
+ if (action instanceof Preparable) {
+ try {
+ PrefixMethodInvocationUtil.invokePrefixMethod(invocation,
+ new String[]{PREPARE_PREFIX, ALT_PREPARE_PREFIX});
+ }
+ catch (InvocationTargetException e) {
+ // just in case there's an exception while doing reflection,
+ // we still want prepare() to be able to get called.
+ LOG.warn("an exception occured while trying to execute prefixed method", e);
+ }
+ catch (IllegalAccessException e) {
+ // just in case there's an exception while doing reflection,
+ // we still want prepare() to be able to get called.
+ LOG.warn("an exception occured while trying to execute prefixed method", e);
+ } catch (Exception e) {
+ // just in case there's an exception while doing reflection,
+ // we still want prepare() to be able to get called.
+ LOG.warn("an exception occured while trying to execute prefixed method", e);
+ }
+
+ if (alwaysInvokePrepare) {
+ ((Preparable) action).prepare();
+ }
+ }
+
+ return invocation.invoke();
+ }
+
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/PrepareInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.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();
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDriven.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Added: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java
URL: http://svn.apache.org/viewvc/struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java?rev=894087&view=auto
==============================================================================
--- struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java (added)
+++ struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java Sun Dec 27 18:00:13 2009
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2002-2006 by OpenSymphony
+ * All rights reserved.
+ */
+package com.opensymphony.xwork2.interceptor;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.XWorkException;
+import com.opensymphony.xwork2.config.entities.ActionConfig;
+import com.opensymphony.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 -->
+ *
+ * <-- Basic usage -->
+ * <interceptor name="scopedModelDriven" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor" />
+ *
+ * <-- Using all available parameters -->
+ * <interceptor name="gangsterForm" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor">
+ * <param name="scope">session</param>
+ * <param name="name">gangsterForm</param>
+ * <param name="className">com.opensymphony.example.GangsterForm</param>
+ * </interceptor>
+ *
+ * <!-- 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;
+ }
+}
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: struts/xwork/trunk/core/src/main/java/com/opensymphony/xwork2/interceptor/ScopedModelDrivenInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL