mirror of
https://github.com/apache/struts.git
synced 2026-08-06 15:17:00 +00:00
Merge pull request #1103 from apache/7.0.x/merge-master-2024-11-01
7.0.x/merge master 2024 11 01
This commit is contained in:
@@ -52,12 +52,12 @@ jobs:
|
||||
java-version: 17
|
||||
cache: 'maven'
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3.26.12
|
||||
uses: github/codeql-action/init@v3.27.0
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3.26.12
|
||||
uses: github/codeql-action/autobuild@v3.27.0
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3.26.12
|
||||
uses: github/codeql-action/analyze@v3.27.0
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
@@ -65,6 +65,6 @@ jobs:
|
||||
retention-days: 5
|
||||
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@ea2cd92c21b192add69983116b8b3222b09da33b # 2.22.11
|
||||
uses: github/codeql-action/upload-sarif@3aa71356c75a8edd8430d54dff2982203a28be45 # 2.22.11
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>it.org.apache.struts2.showcase.*Test</include>
|
||||
|
||||
@@ -19,70 +19,10 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
/**
|
||||
* All actions <b>may</b> implement this interface, which exposes the <code>execute()</code> method.
|
||||
* <p>
|
||||
* However, as of XWork 1.1, this is <b>not</b> required and is only here to assist users. You are free to create POJOs
|
||||
* that honor the same contract defined by this interface without actually implementing the interface.
|
||||
* </p>
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.Action} instead.
|
||||
*/
|
||||
public interface Action {
|
||||
|
||||
/**
|
||||
* The action execution was successful. Show result
|
||||
* view to the end user.
|
||||
*/
|
||||
String SUCCESS = "success";
|
||||
|
||||
/**
|
||||
* The action execution was successful but do not
|
||||
* show a view. This is useful for actions that are
|
||||
* handling the view in another fashion like redirect.
|
||||
*/
|
||||
String NONE = "none";
|
||||
|
||||
/**
|
||||
* The action execution was a failure.
|
||||
* Show an error view, possibly asking the
|
||||
* user to retry entering data.
|
||||
*/
|
||||
String ERROR = "error";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The action execution require more input
|
||||
* in order to succeed.
|
||||
* This result is typically used if a form
|
||||
* handling action has been executed so as
|
||||
* to provide defaults for a form. The
|
||||
* form associated with the handler should be
|
||||
* shown to the end user.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This result is also used if the given input
|
||||
* params are invalid, meaning the user
|
||||
* should try providing input again.
|
||||
* </p>
|
||||
*/
|
||||
String INPUT = "input";
|
||||
|
||||
/**
|
||||
* The action could not execute, since the
|
||||
* user most was not logged in. The login view
|
||||
* should be shown.
|
||||
*/
|
||||
String LOGIN = "login";
|
||||
|
||||
|
||||
/**
|
||||
* Where the logic of the action is executed.
|
||||
*
|
||||
* @return a string representing the logical result of the execution.
|
||||
* See constants in this interface for a list of standard result values.
|
||||
* @throws Exception thrown if a system level exception occurs.
|
||||
* <b>Note:</b> Application level exceptions should be handled by returning
|
||||
* an error value, such as <code>Action.ERROR</code>.
|
||||
*/
|
||||
String execute() throws Exception;
|
||||
|
||||
@Deprecated
|
||||
public interface Action extends org.apache.struts2.Action {
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ package com.opensymphony.xwork2;
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
|
||||
@@ -30,515 +28,249 @@ import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.jsp.PageContext;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The ActionContext is the context in which an {@link Action} is executed. Each context is basically a
|
||||
* container of objects an action needs for execution like the session, parameters, locale, etc.
|
||||
* </p>
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* The ActionContext is thread local which means that values stored in the ActionContext are
|
||||
* unique per thread. See the {@link ThreadLocal} class for more information. The benefit of
|
||||
* this is you don't need to worry about a user specific action context, you just get it:
|
||||
* </p>
|
||||
*
|
||||
* <code>ActionContext context = ActionContext.getContext();</code>
|
||||
*
|
||||
* <p>
|
||||
* Finally, because of the thread local usage you don't need to worry about making your actions thread safe.
|
||||
* </p>
|
||||
*
|
||||
* @author Patrick Lightbody
|
||||
* @author Bill Lynch (docs)
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ActionContext} instead.
|
||||
*/
|
||||
public class ActionContext implements Serializable {
|
||||
@Deprecated
|
||||
public class ActionContext extends org.apache.struts2.ActionContext {
|
||||
|
||||
private static final ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Constant for the name of the action being executed.
|
||||
*/
|
||||
private static final String ACTION_NAME = "org.apache.struts2.ActionContext.name";
|
||||
|
||||
/**
|
||||
* Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}.
|
||||
*/
|
||||
private static final String VALUE_STACK = ValueStack.VALUE_STACK;
|
||||
|
||||
/**
|
||||
* Constant for the action's session.
|
||||
*/
|
||||
private static final String SESSION = "org.apache.struts2.ActionContext.session";
|
||||
|
||||
/**
|
||||
* Constant for the action's application context.
|
||||
*/
|
||||
private static final String APPLICATION = "org.apache.struts2.ActionContext.application";
|
||||
|
||||
/**
|
||||
* Constant for the action's parameters.
|
||||
*/
|
||||
private static final String PARAMETERS = "org.apache.struts2.ActionContext.parameters";
|
||||
|
||||
/**
|
||||
* Constant for the action's locale.
|
||||
*/
|
||||
private static final String LOCALE = "org.apache.struts2.ActionContext.locale";
|
||||
|
||||
/**
|
||||
* Constant for the action's {@link com.opensymphony.xwork2.ActionInvocation invocation} context.
|
||||
*/
|
||||
private static final String ACTION_INVOCATION = "org.apache.struts2.ActionContext.actionInvocation";
|
||||
|
||||
/**
|
||||
* Constant for the map of type conversion errors.
|
||||
*/
|
||||
private static final String CONVERSION_ERRORS = "org.apache.struts2.ActionContext.conversionErrors";
|
||||
|
||||
/**
|
||||
* Constant for the container
|
||||
*/
|
||||
private static final String CONTAINER = "org.apache.struts2.ActionContext.container";
|
||||
|
||||
private final Map<String, Object> context;
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext initialized with another context.
|
||||
*
|
||||
* @param context a context map.
|
||||
*/
|
||||
protected ActionContext(Map<String, Object> context) {
|
||||
this.context = context;
|
||||
private ActionContext(org.apache.struts2.ActionContext actualContext) {
|
||||
super(actualContext.getContextMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on passed in Map
|
||||
*
|
||||
* @param context a map with context values
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of(Map<String, Object> context) {
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("Context cannot be null!");
|
||||
public static ActionContext adapt(org.apache.struts2.ActionContext actualContext) {
|
||||
if (actualContext instanceof ActionContext) {
|
||||
return (ActionContext) actualContext;
|
||||
}
|
||||
return new ActionContext(context);
|
||||
return actualContext != null ? new ActionContext(actualContext) : null;
|
||||
}
|
||||
|
||||
public static ActionContext of(Map<String, Object> context) {
|
||||
return adapt(org.apache.struts2.ActionContext.of(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on empty Map
|
||||
*
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of() {
|
||||
return of(new HashMap<>());
|
||||
return adapt(org.apache.struts2.ActionContext.of());
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the provided context with the current thread
|
||||
*
|
||||
* @param actionContext context to bind to the thread
|
||||
* @return context which was bound to the thread
|
||||
*/
|
||||
public static ActionContext bind(ActionContext actionContext) {
|
||||
ActionContext.setContext(actionContext);
|
||||
return ActionContext.getContext();
|
||||
return adapt(org.apache.struts2.ActionContext.bind(actionContext));
|
||||
}
|
||||
|
||||
public static boolean containsValueStack(Map<String, Object> context) {
|
||||
return context != null && context.containsKey(VALUE_STACK);
|
||||
return org.apache.struts2.ActionContext.containsValueStack(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds this context with the current thread
|
||||
*
|
||||
* @return this context which was bound to the thread
|
||||
*/
|
||||
public ActionContext bind() {
|
||||
ActionContext.setContext(this);
|
||||
return ActionContext.getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipes out current ActionContext, use wisely!
|
||||
*/
|
||||
public static void clear() {
|
||||
actionContext.remove();
|
||||
org.apache.struts2.ActionContext.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action context for the current thread.
|
||||
*
|
||||
* @param context the action context.
|
||||
*/
|
||||
private static void setContext(ActionContext context) {
|
||||
actionContext.set(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ActionContext specific to the current thread.
|
||||
*
|
||||
* @return the ActionContext for the current thread, is never <tt>null</tt>.
|
||||
*/
|
||||
public static ActionContext getContext() {
|
||||
return actionContext.get();
|
||||
return adapt(org.apache.struts2.ActionContext.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext bind() {
|
||||
super.bind();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action invocation (the execution state).
|
||||
*
|
||||
* @param actionInvocation the action execution state.
|
||||
*/
|
||||
public ActionContext withActionInvocation(ActionInvocation actionInvocation) {
|
||||
put(ACTION_INVOCATION, actionInvocation);
|
||||
return withActionInvocation((org.apache.struts2.ActionInvocation) actionInvocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext withActionInvocation(org.apache.struts2.ActionInvocation actionInvocation) {
|
||||
super.withActionInvocation(actionInvocation);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the action invocation (the execution state).
|
||||
*
|
||||
* @return the action invocation (the execution state).
|
||||
*/
|
||||
@Override
|
||||
public ActionInvocation getActionInvocation() {
|
||||
return (ActionInvocation) get(ACTION_INVOCATION);
|
||||
return ActionInvocation.adapt(super.getActionInvocation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action's application context.
|
||||
*
|
||||
* @param application the action's application context.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withApplication(Map<String, Object> application) {
|
||||
put(APPLICATION, application);
|
||||
super.withApplication(application);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of the ServletContext when in a servlet environment or a generic application level Map otherwise.
|
||||
*
|
||||
* @return a Map of ServletContext or generic application level Map
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, Object> getApplication() {
|
||||
return (Map<String, Object>) get(APPLICATION);
|
||||
return super.getApplication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context map.
|
||||
*
|
||||
* @return the context map.
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getContextMap() {
|
||||
return context;
|
||||
return super.getContextMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @param conversionErrors a Map of errors which occurred when executing the action.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withConversionErrors(Map<String, ConversionData> conversionErrors) {
|
||||
put(CONVERSION_ERRORS, conversionErrors);
|
||||
super.withConversionErrors(conversionErrors);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the map of conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @return the map of conversion errors which occurred when executing the action or an empty map if
|
||||
* there were no errors.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, ConversionData> getConversionErrors() {
|
||||
Map<String, ConversionData> errors = (Map<String, ConversionData>) get(CONVERSION_ERRORS);
|
||||
|
||||
if (errors == null) {
|
||||
errors = withConversionErrors(new HashMap<>()).getConversionErrors();
|
||||
}
|
||||
|
||||
return errors;
|
||||
return super.getConversionErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Locale for the current action.
|
||||
*
|
||||
* @param locale the Locale for the current action.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withLocale(Locale locale) {
|
||||
put(LOCALE, locale);
|
||||
super.withLocale(locale);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Locale of the current action. If no locale was ever specified the platform's
|
||||
* {@link java.util.Locale#getDefault() default locale} is used.
|
||||
*
|
||||
* @return the Locale of the current action.
|
||||
*/
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
Locale locale = (Locale) get(LOCALE);
|
||||
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
withLocale(locale);
|
||||
}
|
||||
|
||||
return locale;
|
||||
return super.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the current Action in the ActionContext.
|
||||
*
|
||||
* @param actionName the name of the current action.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withActionName(String actionName) {
|
||||
put(ACTION_NAME, actionName);
|
||||
super.withActionName(actionName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the current Action.
|
||||
*
|
||||
* @return the name of the current action.
|
||||
*/
|
||||
@Override
|
||||
public String getActionName() {
|
||||
return (String) get(ACTION_NAME);
|
||||
return super.getActionName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action parameters.
|
||||
*
|
||||
* @param parameters the parameters for the current action.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withParameters(HttpParameters parameters) {
|
||||
put(PARAMETERS, parameters);
|
||||
super.withParameters(parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of the HttpServletRequest parameters when in a servlet environment or a generic Map of
|
||||
* parameters otherwise.
|
||||
*
|
||||
* @return a Map of HttpServletRequest parameters or a multipart map when in a servlet environment, or a
|
||||
* generic Map of parameters otherwise.
|
||||
*/
|
||||
@Override
|
||||
public HttpParameters getParameters() {
|
||||
return (HttpParameters) get(PARAMETERS);
|
||||
return super.getParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of action session values.
|
||||
*
|
||||
* @param session the session values.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withSession(Map<String, Object> session) {
|
||||
put(SESSION, session);
|
||||
super.withSession(session);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
|
||||
*
|
||||
* @return the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, Object> getSession() {
|
||||
return (Map<String, Object>) get(SESSION);
|
||||
return super.getSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OGNL value stack.
|
||||
*
|
||||
* @param valueStack the OGNL value stack.
|
||||
*/
|
||||
public ActionContext withValueStack(ValueStack valueStack) {
|
||||
put(VALUE_STACK, valueStack);
|
||||
return withValueStack((org.apache.struts2.util.ValueStack) valueStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext withValueStack(org.apache.struts2.util.ValueStack valueStack) {
|
||||
super.withValueStack(valueStack);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OGNL value stack.
|
||||
*
|
||||
* @return the OGNL value stack.
|
||||
*/
|
||||
@Override
|
||||
public ValueStack getValueStack() {
|
||||
return (ValueStack) get(VALUE_STACK);
|
||||
return ValueStack.adapt(super.getValueStack());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the container for this request
|
||||
*
|
||||
* @param container The container
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withContainer(Container container) {
|
||||
put(CONTAINER, container);
|
||||
super.withContainer(container);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the container for this request
|
||||
*
|
||||
* @return The container
|
||||
*/
|
||||
@Override
|
||||
public Container getContainer() {
|
||||
return (Container) get(CONTAINER);
|
||||
return super.getContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(Class<T> type) {
|
||||
Container cont = getContainer();
|
||||
if (cont != null) {
|
||||
return cont.getInstance(type);
|
||||
} else {
|
||||
throw new StrutsException("Cannot find an initialized container for this request.");
|
||||
}
|
||||
return super.getInstance(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.
|
||||
*
|
||||
* @param key the key used to find the value.
|
||||
* @return the value that was found using the key or <tt>null</tt> if the key was not found.
|
||||
*/
|
||||
@Override
|
||||
public Object get(String key) {
|
||||
return context.get(key);
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value in the current ActionContext. The value can be looked up using the key.
|
||||
*
|
||||
* @param key the key of the value.
|
||||
* @param value the value to be stored.
|
||||
*/
|
||||
@Override
|
||||
public void put(String key, Object value) {
|
||||
context.put(key, value);
|
||||
super.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletContext associated with current action
|
||||
*
|
||||
* @return current ServletContext
|
||||
*/
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
return (ServletContext) get(StrutsStatics.SERVLET_CONTEXT);
|
||||
return super.getServletContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletContext to action context
|
||||
*
|
||||
* @param servletContext associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withServletContext(ServletContext servletContext) {
|
||||
put(StrutsStatics.SERVLET_CONTEXT, servletContext);
|
||||
super.withServletContext(servletContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletRequest associated with current action
|
||||
*
|
||||
* @return current ServletRequest
|
||||
*/
|
||||
@Override
|
||||
public HttpServletRequest getServletRequest() {
|
||||
return (HttpServletRequest) get(StrutsStatics.HTTP_REQUEST);
|
||||
return super.getServletRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletRequest to action context
|
||||
*
|
||||
* @param request associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withServletRequest(HttpServletRequest request) {
|
||||
put(StrutsStatics.HTTP_REQUEST, request);
|
||||
super.withServletRequest(request);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletResponse associated with current action
|
||||
*
|
||||
* @return current ServletResponse
|
||||
*/
|
||||
@Override
|
||||
public HttpServletResponse getServletResponse() {
|
||||
return (HttpServletResponse) get(StrutsStatics.HTTP_RESPONSE);
|
||||
return super.getServletResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletResponse to action context
|
||||
*
|
||||
* @param response associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withServletResponse(HttpServletResponse response) {
|
||||
put(StrutsStatics.HTTP_RESPONSE, response);
|
||||
super.withServletResponse(response);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets PageContext associated with current action
|
||||
*
|
||||
* @return current PageContext
|
||||
*/
|
||||
@Override
|
||||
public PageContext getPageContext() {
|
||||
return (PageContext) get(StrutsStatics.PAGE_CONTEXT);
|
||||
return super.getPageContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns PageContext to action context
|
||||
*
|
||||
* @param pageContext associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withPageContext(PageContext pageContext) {
|
||||
put(StrutsStatics.PAGE_CONTEXT, pageContext);
|
||||
super.withPageContext(pageContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ActionMapping associated with current action
|
||||
*
|
||||
* @return current ActionMapping
|
||||
*/
|
||||
@Override
|
||||
public ActionMapping getActionMapping() {
|
||||
return (ActionMapping) get(StrutsStatics.ACTION_MAPPING);
|
||||
return super.getActionMapping();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ActionMapping to action context
|
||||
*
|
||||
* @param actionMapping associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withActionMapping(ActionMapping actionMapping) {
|
||||
put(StrutsStatics.ACTION_MAPPING, actionMapping);
|
||||
super.withActionMapping(actionMapping);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns an extra context map to action context
|
||||
*
|
||||
* @param extraContext to add to the current action context
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withExtraContext(Map<String, Object> extraContext) {
|
||||
if (extraContext != null) {
|
||||
context.putAll(extraContext);
|
||||
}
|
||||
super.withExtraContext(extraContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds arbitrary key to action context
|
||||
*
|
||||
* @param key a string
|
||||
* @param value an object
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext with(String key, Object value) {
|
||||
put(key, value);
|
||||
super.with(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,24 +21,50 @@ package com.opensymphony.xwork2;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
/**
|
||||
* Provides hooks for handling key action events
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ActionEventListener} instead.
|
||||
*/
|
||||
public interface ActionEventListener {
|
||||
/**
|
||||
* Called after an action has been created.
|
||||
*
|
||||
* @param action The action
|
||||
* @param stack The current value stack
|
||||
* @return The action to use
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ActionEventListener extends org.apache.struts2.ActionEventListener {
|
||||
|
||||
@Override
|
||||
default Object prepare(Object action, org.apache.struts2.util.ValueStack stack) {
|
||||
return prepare(action, ValueStack.adapt(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
default String handleException(Throwable t, org.apache.struts2.util.ValueStack stack) {
|
||||
return handleException(t, ValueStack.adapt(stack));
|
||||
}
|
||||
|
||||
Object prepare(Object action, ValueStack stack);
|
||||
|
||||
/**
|
||||
* Called when an exception is thrown by the action
|
||||
*
|
||||
* @param t The exception/error that was thrown
|
||||
* @param stack The current value stack
|
||||
* @return A result code to execute, can be null
|
||||
*/
|
||||
String handleException(Throwable t, ValueStack stack);
|
||||
|
||||
static ActionEventListener adapt(org.apache.struts2.ActionEventListener actualListener) {
|
||||
if (actualListener instanceof ActionEventListener) {
|
||||
return (ActionEventListener) actualListener;
|
||||
}
|
||||
return actualListener != null ? new LegacyAdapter(actualListener) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements ActionEventListener {
|
||||
|
||||
private final org.apache.struts2.ActionEventListener adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.ActionEventListener adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object prepare(Object action, ValueStack stack) {
|
||||
return adaptee.prepare(action, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handleException(Throwable t, ValueStack stack) {
|
||||
return adaptee.handleException(t, stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,158 +22,125 @@ import com.opensymphony.xwork2.interceptor.PreResultListener;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
/**
|
||||
* An {@link ActionInvocation} represents the execution state of an {@link Action}. It holds the Interceptors and the Action instance.
|
||||
* By repeated re-entrant execution of the <code>invoke()</code> method, initially by the {@link ActionProxy}, then by the Interceptors, the
|
||||
* Interceptors are all executed, and then the {@link Action} and the {@link Result}.
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see com.opensymphony.xwork2.ActionProxy
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ActionInvocation} instead.
|
||||
*/
|
||||
public interface ActionInvocation {
|
||||
@Deprecated
|
||||
public interface ActionInvocation extends org.apache.struts2.ActionInvocation {
|
||||
|
||||
/**
|
||||
* Get the Action associated with this ActionInvocation.
|
||||
*
|
||||
* @return the Action
|
||||
*/
|
||||
Object getAction();
|
||||
|
||||
/**
|
||||
* Gets whether this ActionInvocation has executed before.
|
||||
* This will be set after the Action and the Result have executed.
|
||||
*
|
||||
* @return <tt>true</tt> if this ActionInvocation has executed before.
|
||||
*/
|
||||
boolean isExecuted();
|
||||
|
||||
/**
|
||||
* Gets the ActionContext associated with this ActionInvocation. The ActionProxy is
|
||||
* responsible for setting this ActionContext onto the ThreadLocal before invoking
|
||||
* the ActionInvocation and resetting the old ActionContext afterwards.
|
||||
*
|
||||
* @return the ActionContext.
|
||||
*/
|
||||
@Override
|
||||
ActionContext getInvocationContext();
|
||||
|
||||
/**
|
||||
* Get the ActionProxy holding this ActionInvocation.
|
||||
*
|
||||
* @return the ActionProxy.
|
||||
*/
|
||||
ActionProxy getProxy();
|
||||
|
||||
/**
|
||||
* If the ActionInvocation has been executed before and the Result is an instance of {@link ActionChainResult}, this method
|
||||
* will walk down the chain of <code>ActionChainResult</code>s until it finds a non-chain result, which will be returned. If the
|
||||
* ActionInvocation's result has not been executed before, the Result instance will be created and populated with
|
||||
* the result params.
|
||||
*
|
||||
* @return the result.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
@Override
|
||||
Result getResult() throws Exception;
|
||||
|
||||
/**
|
||||
* Gets the result code returned from this ActionInvocation.
|
||||
*
|
||||
* @return the result code
|
||||
*/
|
||||
String getResultCode();
|
||||
@Override
|
||||
ActionProxy getProxy();
|
||||
|
||||
/**
|
||||
* Sets the result code, possibly overriding the one returned by the
|
||||
* action.
|
||||
*
|
||||
* <p>
|
||||
* The "intended" purpose of this method is to allow PreResultListeners to
|
||||
* override the result code returned by the Action.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is used before the Action executes, the Action's returned
|
||||
* result code will override what was set. However the Action could (if
|
||||
* specifically coded to do so) inspect the ActionInvocation to see that
|
||||
* someone "upstream" (e.g. an Interceptor) had suggested a value as the
|
||||
* result, and it could therefore return the same value itself.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is called between the Action execution and the Result
|
||||
* execution, then the value set here will override the result code the
|
||||
* action had returned. Creating an Interceptor that implements
|
||||
* {@link PreResultListener} will give you this opportunity.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is called after the Result has been executed, it will
|
||||
* have the effect of raising an IllegalStateException.
|
||||
* </p>
|
||||
*
|
||||
* @param resultCode the result code.
|
||||
* @throws IllegalStateException if called after the Result has been executed.
|
||||
* @see #isExecuted()
|
||||
*/
|
||||
void setResultCode(String resultCode);
|
||||
|
||||
/**
|
||||
* Gets the ValueStack associated with this ActionInvocation.
|
||||
*
|
||||
* @return the ValueStack
|
||||
*/
|
||||
@Override
|
||||
ValueStack getStack();
|
||||
|
||||
/**
|
||||
* Register a {@link PreResultListener} to be notified after the Action is executed and
|
||||
* before the Result is executed.
|
||||
*
|
||||
* <p>
|
||||
* The ActionInvocation implementation must guarantee that listeners will be called in
|
||||
* the order in which they are registered.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Listener registration and execution does not need to be thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @param listener the listener to add.
|
||||
*/
|
||||
@Override
|
||||
default void addPreResultListener(org.apache.struts2.interceptor.PreResultListener listener) {
|
||||
addPreResultListener(PreResultListener.adapt(listener));
|
||||
}
|
||||
|
||||
void addPreResultListener(PreResultListener listener);
|
||||
|
||||
/**
|
||||
* Invokes the next step in processing this ActionInvocation.
|
||||
*
|
||||
* <p>
|
||||
* If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit
|
||||
* ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor
|
||||
* to execute. If there are no more Interceptors to be applied, the Action is executed.
|
||||
* If the {@link ActionProxy#getExecuteResult()} method returns <tt>true</tt>, the Result is also executed.
|
||||
* </p>
|
||||
*
|
||||
* @throws Exception can be thrown.
|
||||
* @return the return code.
|
||||
*/
|
||||
String invoke() throws Exception;
|
||||
@Override
|
||||
default void setActionEventListener(org.apache.struts2.ActionEventListener listener) {
|
||||
setActionEventListener(ActionEventListener.adapt(listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes only the Action (not Interceptors or Results).
|
||||
*
|
||||
* <p>
|
||||
* This is useful in rare situations where advanced usage with the interceptor/action/result workflow is
|
||||
* being manipulated for certain functionality.
|
||||
* </p>
|
||||
*
|
||||
* @return the return code.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
String invokeActionOnly() throws Exception;
|
||||
|
||||
/**
|
||||
* Sets the action event listener to respond to key action events.
|
||||
*
|
||||
* @param listener the listener.
|
||||
*/
|
||||
void setActionEventListener(ActionEventListener listener);
|
||||
|
||||
void init(ActionProxy proxy) ;
|
||||
@Override
|
||||
default void init(org.apache.struts2.ActionProxy proxy) {
|
||||
init(ActionProxy.adapt(proxy));
|
||||
}
|
||||
|
||||
void init(ActionProxy proxy);
|
||||
|
||||
static ActionInvocation adapt(org.apache.struts2.ActionInvocation actualInvocation) {
|
||||
if (actualInvocation instanceof ActionInvocation) {
|
||||
return (ActionInvocation) actualInvocation;
|
||||
}
|
||||
return actualInvocation != null ? new LegacyAdapter(actualInvocation) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements ActionInvocation {
|
||||
|
||||
private final org.apache.struts2.ActionInvocation adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.ActionInvocation adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAction() {
|
||||
return adaptee.getAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExecuted() {
|
||||
return adaptee.isExecuted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext getInvocationContext() {
|
||||
return ActionContext.adapt(adaptee.getInvocationContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProxy getProxy() {
|
||||
return ActionProxy.adapt(adaptee.getProxy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result getResult() throws Exception {
|
||||
return Result.adapt(adaptee.getResult());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultCode() {
|
||||
return adaptee.getResultCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResultCode(String resultCode) {
|
||||
adaptee.setResultCode(resultCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueStack getStack() {
|
||||
return ValueStack.adapt(adaptee.getStack());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPreResultListener(PreResultListener listener) {
|
||||
adaptee.addPreResultListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String invoke() throws Exception {
|
||||
return adaptee.invoke();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String invokeActionOnly() throws Exception {
|
||||
return adaptee.invokeActionOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionEventListener(ActionEventListener listener) {
|
||||
adaptee.setActionEventListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(ActionProxy proxy) {
|
||||
adaptee.init(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,88 +20,75 @@ package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
|
||||
/**
|
||||
* ActionProxy is an extra layer between XWork and the action so that different proxies are possible.
|
||||
*
|
||||
* <p>
|
||||
* An example of this would be a remote proxy, where the layer between XWork and the action might be RMI or SOAP.
|
||||
* </p>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*/
|
||||
public interface ActionProxy {
|
||||
@Deprecated
|
||||
public interface ActionProxy extends org.apache.struts2.ActionProxy {
|
||||
|
||||
/**
|
||||
* Gets the Action instance for this Proxy.
|
||||
*
|
||||
* @return the Action instance
|
||||
*/
|
||||
Object getAction();
|
||||
|
||||
/**
|
||||
* Gets the alias name this ActionProxy is mapped to.
|
||||
*
|
||||
* @return the alias name
|
||||
*/
|
||||
String getActionName();
|
||||
|
||||
/**
|
||||
* Gets the ActionConfig this ActionProxy is built from.
|
||||
*
|
||||
* @return the ActionConfig
|
||||
*/
|
||||
ActionConfig getConfig();
|
||||
|
||||
/**
|
||||
* Sets whether this ActionProxy should also execute the Result after executing the Action.
|
||||
*
|
||||
* @param executeResult <tt>true</tt> to also execute the Result.
|
||||
*/
|
||||
void setExecuteResult(boolean executeResult);
|
||||
|
||||
/**
|
||||
* Gets the status of whether the ActionProxy is set to execute the Result after the Action is executed.
|
||||
*
|
||||
* @return the status
|
||||
*/
|
||||
boolean getExecuteResult();
|
||||
|
||||
/**
|
||||
* Gets the ActionInvocation associated with this ActionProxy.
|
||||
*
|
||||
* @return the ActionInvocation
|
||||
*/
|
||||
@Override
|
||||
ActionInvocation getInvocation();
|
||||
|
||||
/**
|
||||
* Gets the namespace the ActionConfig for this ActionProxy is mapped to.
|
||||
*
|
||||
* @return the namespace
|
||||
*/
|
||||
String getNamespace();
|
||||
static ActionProxy adapt(org.apache.struts2.ActionProxy actualProxy) {
|
||||
if (actualProxy instanceof ActionProxy) {
|
||||
return (ActionProxy) actualProxy;
|
||||
}
|
||||
return actualProxy != null ? new LegacyAdapter(actualProxy) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute this ActionProxy. This will set the ActionContext from the ActionInvocation into the ActionContext
|
||||
* ThreadLocal before invoking the ActionInvocation, then set the old ActionContext back into the ThreadLocal.
|
||||
*
|
||||
* @return the result code returned from executing the ActionInvocation
|
||||
* @throws Exception can be thrown.
|
||||
* @see ActionInvocation
|
||||
*/
|
||||
String execute() throws Exception;
|
||||
class LegacyAdapter implements ActionProxy {
|
||||
|
||||
/**
|
||||
* Gets the method name to execute, or <tt>null</tt> if no method has been specified (meaning <code>execute</code> will be invoked).
|
||||
*
|
||||
* @return the method to execute
|
||||
*/
|
||||
String getMethod();
|
||||
private final org.apache.struts2.ActionProxy adaptee;
|
||||
|
||||
/**
|
||||
* Gets status of the method value's initialization.
|
||||
*
|
||||
* @return true if the method returned by getMethod() is not a default initializer value.
|
||||
*/
|
||||
boolean isMethodSpecified();
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.ActionProxy adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAction() {
|
||||
return adaptee.getAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionName() {
|
||||
return adaptee.getActionName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionConfig getConfig() {
|
||||
return adaptee.getConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExecuteResult(boolean executeResult) {
|
||||
adaptee.setExecuteResult(executeResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getExecuteResult() {
|
||||
return adaptee.getExecuteResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionInvocation getInvocation() {
|
||||
return ActionInvocation.adapt(adaptee.getInvocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return adaptee.getNamespace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
return adaptee.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return adaptee.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMethodSpecified() {
|
||||
return adaptee.isMethodSpecified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,346 +18,11 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Provides a default implementation for the most common actions.
|
||||
* See the documentation for all the interfaces this class implements for more detailed information.
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ActionSupport} instead.
|
||||
*/
|
||||
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ActionSupport.class);
|
||||
|
||||
private final ValidationAwareSupport validationAware = new ValidationAwareSupport();
|
||||
|
||||
private transient TextProvider textProvider;
|
||||
private transient LocaleProvider localeProvider;
|
||||
|
||||
protected Container container;
|
||||
|
||||
@Override
|
||||
public void setActionErrors(Collection<String> errorMessages) {
|
||||
validationAware.setActionErrors(errorMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionErrors() {
|
||||
return validationAware.getActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionMessages(Collection<String> messages) {
|
||||
validationAware.setActionMessages(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionMessages() {
|
||||
return validationAware.getActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFieldErrors(Map<String, List<String>> errorMap) {
|
||||
validationAware.setFieldErrors(errorMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getFieldErrors() {
|
||||
return validationAware.getFieldErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return getLocaleProvider().getLocale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocaleString(String localeStr) {
|
||||
return getLocaleProvider().isValidLocaleString(localeStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocale(Locale locale) {
|
||||
return getLocaleProvider().isValidLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale toLocale(String localeStr) {
|
||||
return getLocaleProvider().toLocale(localeStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey(String key) {
|
||||
return getTextProvider().hasKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName) {
|
||||
return getTextProvider().getText(aTextName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue) {
|
||||
return getTextProvider().getText(aTextName, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue, String obj) {
|
||||
return getTextProvider().getText(aTextName, defaultValue, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, List<?> args) {
|
||||
return getTextProvider().getText(aTextName, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String[] args) {
|
||||
return getTextProvider().getText(key, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue, List<?> args) {
|
||||
return getTextProvider().getText(aTextName, defaultValue, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, String[] args) {
|
||||
return getTextProvider().getText(key, defaultValue, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
|
||||
return getTextProvider().getText(key, defaultValue, args, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
|
||||
return getTextProvider().getText(key, defaultValue, args, stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedicated method to support I10N and conversion errors
|
||||
*
|
||||
* @param key message which contains formatting string
|
||||
* @param expr that should be formatted
|
||||
* @return formatted expr with format specified by key
|
||||
*/
|
||||
public String getFormatted(String key, String expr) {
|
||||
Map<String, ConversionData> conversionErrors = ActionContext.getContext().getConversionErrors();
|
||||
if (conversionErrors.containsKey(expr)) {
|
||||
String[] vals = (String[]) conversionErrors.get(expr).getValue();
|
||||
return vals[0];
|
||||
} else {
|
||||
final ValueStack valueStack = ActionContext.getContext().getValueStack();
|
||||
final Object val = valueStack.findValue(expr);
|
||||
return getText(key, List.of(val));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundle getTexts() {
|
||||
return getTextProvider().getTexts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundle getTexts(String aBundleName) {
|
||||
return getTextProvider().getTexts(aBundleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionError(String anErrorMessage) {
|
||||
validationAware.addActionError(anErrorMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionMessage(String aMessage) {
|
||||
validationAware.addActionMessage(aMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFieldError(String fieldName, String errorMessage) {
|
||||
validationAware.addFieldError(fieldName, errorMessage);
|
||||
}
|
||||
|
||||
public String input() throws Exception {
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* A default implementation that does nothing an returns "success".
|
||||
*
|
||||
* <p>
|
||||
* Subclasses should override this method to provide their business logic.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* See also {@link com.opensymphony.xwork2.Action#execute()}.
|
||||
* </p>
|
||||
*
|
||||
* @return returns {@link #SUCCESS}
|
||||
* @throws Exception can be thrown by subclasses.
|
||||
*/
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionErrors() {
|
||||
return validationAware.hasActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionMessages() {
|
||||
return validationAware.hasActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasErrors() {
|
||||
return validationAware.hasErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFieldErrors() {
|
||||
return validationAware.hasFieldErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears field errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearFieldErrors() {
|
||||
validationAware.clearFieldErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears action errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearActionErrors() {
|
||||
validationAware.clearActionErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears messages. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearMessages() {
|
||||
validationAware.clearMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearErrors() {
|
||||
validationAware.clearErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all errors and messages. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearErrorsAndMessages() {
|
||||
validationAware.clearErrorsAndMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* A default implementation that validates nothing.
|
||||
* Subclasses should override this method to provide validations.
|
||||
*/
|
||||
@Override
|
||||
public void validate() {
|
||||
// A default implementation that validates nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: pause-method -->
|
||||
* Stops the action invocation immediately (by throwing a PauseException) and causes the action invocation to return
|
||||
* the specified result, such as {@link #SUCCESS}, {@link #INPUT}, etc.
|
||||
*
|
||||
* <p>
|
||||
* The next time this action is invoked (and using the same continuation ID), the method will resume immediately
|
||||
* after where this method was called, with the entire call stack in the execute method restored.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note: this method can <b>only</b> be called within the {@link #execute()} method.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: pause-method -->
|
||||
*
|
||||
* @param result the result to return - the same type of return value in the {@link #execute()} method.
|
||||
*/
|
||||
public void pause(String result) {
|
||||
}
|
||||
|
||||
/**
|
||||
* If called first time it will create {@link com.opensymphony.xwork2.TextProviderFactory},
|
||||
* inject dependency (if {@link com.opensymphony.xwork2.inject.Container} is accesible) into in,
|
||||
* then will create new {@link com.opensymphony.xwork2.TextProvider} and store it in a field
|
||||
* for future references and at the returns reference to that field
|
||||
*
|
||||
* @return reference to field with TextProvider
|
||||
*/
|
||||
protected TextProvider getTextProvider() {
|
||||
if (textProvider == null) {
|
||||
final TextProviderFactory tpf = getContainer().getInstance(TextProviderFactory.class);
|
||||
textProvider = tpf.createInstance(getClass());
|
||||
}
|
||||
return textProvider;
|
||||
}
|
||||
|
||||
protected LocaleProvider getLocaleProvider() {
|
||||
if (localeProvider == null) {
|
||||
final LocaleProviderFactory localeProviderFactory = getContainer().getInstance(LocaleProviderFactory.class);
|
||||
localeProvider = localeProviderFactory.createLocaleProvider();
|
||||
}
|
||||
return localeProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This a temporary solution, maybe we should consider stop injecting container into beans
|
||||
*/
|
||||
protected Container getContainer() {
|
||||
if (container == null) {
|
||||
container = ActionContext.getContext().getContainer();
|
||||
if (container != null) {
|
||||
boolean devMode = Boolean.parseBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_DEVMODE));
|
||||
if (devMode) {
|
||||
LOG.warn("Container is null, action was created manually? Fallback to ActionContext");
|
||||
} else {
|
||||
LOG.debug("Container is null, action was created manually? Fallback to ActionContext");
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Container is null, action was created out of ActionContext scope?!?");
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setContainer(Container container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public class ActionSupport extends org.apache.struts2.ActionSupport implements Action, Validateable, ValidationAware {
|
||||
}
|
||||
|
||||
@@ -258,6 +258,9 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
Interceptor interceptor = interceptorMapping.getInterceptor();
|
||||
if (interceptor instanceof WithLazyParams) {
|
||||
interceptor = lazyParamInjector.injectParams(interceptor, interceptorMapping.getParams(), invocationContext);
|
||||
} else if (interceptor instanceof Interceptor.LegacyAdapter && ((Interceptor.LegacyAdapter) interceptor).getAdaptee() instanceof WithLazyParams) {
|
||||
org.apache.struts2.interceptor.Interceptor adaptee = ((Interceptor.LegacyAdapter) interceptor).getAdaptee();
|
||||
lazyParamInjector.injectParams(adaptee, interceptorMapping.getParams(), invocationContext);
|
||||
}
|
||||
if (interceptor instanceof ConditionalInterceptor) {
|
||||
resultCode = executeConditional((ConditionalInterceptor) interceptor);
|
||||
|
||||
@@ -18,25 +18,9 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
/**
|
||||
* ModelDriven Actions provide a model object to be pushed onto the ValueStack
|
||||
* in addition to the Action itself, allowing a FormBean type approach like Struts.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ModelDriven} instead.
|
||||
*/
|
||||
public interface ModelDriven<T> {
|
||||
|
||||
/**
|
||||
* Gets the model to be pushed onto the ValueStack instead of the Action itself.
|
||||
* <p>
|
||||
* Please be aware that all setters and getters of every depth on the object returned by this method are available
|
||||
* for user parameter injection!
|
||||
*
|
||||
* @return the model
|
||||
*/
|
||||
@StrutsParameter(depth = Integer.MAX_VALUE)
|
||||
T getModel();
|
||||
|
||||
@Deprecated
|
||||
public interface ModelDriven<T> extends org.apache.struts2.ModelDriven<T> {
|
||||
}
|
||||
|
||||
@@ -19,19 +19,8 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
/**
|
||||
* Preparable Actions will have their <code>prepare()</code> method called if the {@link com.opensymphony.xwork2.interceptor.PrepareInterceptor}
|
||||
* is applied to the ActionConfig.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see com.opensymphony.xwork2.interceptor.PrepareInterceptor
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.Preparable} instead.
|
||||
*/
|
||||
public interface Preparable {
|
||||
|
||||
/**
|
||||
* This method is called to allow the action to prepare itself.
|
||||
*
|
||||
* @throws Exception thrown if a system level exception occurs.
|
||||
*/
|
||||
void prepare() throws Exception;
|
||||
|
||||
@Deprecated
|
||||
public interface Preparable extends org.apache.struts2.Preparable {
|
||||
}
|
||||
|
||||
@@ -18,33 +18,39 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* All results (except for <code>Action.NONE</code>) of an {@link Action} are mapped to a View implementation.
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Examples of Views might be:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>SwingPanelView - pops up a new Swing panel</li>
|
||||
* <li>ActionChainView - executes another action</li>
|
||||
* <li>SerlvetRedirectView - redirects the HTTP response to a URL</li>
|
||||
* <li>ServletDispatcherView - dispatches the HTTP response to a URL</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author plightbo
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.Result} instead.
|
||||
*/
|
||||
public interface Result extends Serializable {
|
||||
@Deprecated
|
||||
public interface Result extends org.apache.struts2.Result {
|
||||
|
||||
@Override
|
||||
default void execute(org.apache.struts2.ActionInvocation invocation) throws Exception {
|
||||
execute(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a generic interface for all action execution results.
|
||||
* Whether that be displaying a webpage, generating an email, sending a JMS message, etc.
|
||||
*
|
||||
* @param invocation the invocation context.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
void execute(ActionInvocation invocation) throws Exception;
|
||||
|
||||
static Result adapt(org.apache.struts2.Result actualResult) {
|
||||
if (actualResult instanceof Result) {
|
||||
return (Result) actualResult;
|
||||
}
|
||||
return actualResult != null ? new LegacyAdapter(actualResult) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements Result {
|
||||
|
||||
private final org.apache.struts2.Result adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.Result adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ActionInvocation invocation) throws Exception {
|
||||
adaptee.execute(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
/**
|
||||
* Simple marker interface to indicate an object should <b>not</b> have its properties copied during chaining.
|
||||
*
|
||||
* @see com.opensymphony.xwork2.interceptor.ChainingInterceptor
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.Unchainable} instead.
|
||||
*/
|
||||
public interface Unchainable {
|
||||
@Deprecated
|
||||
public interface Unchainable extends org.apache.struts2.Unchainable {
|
||||
}
|
||||
|
||||
@@ -19,17 +19,8 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
/**
|
||||
* Provides an interface in which a call for a validation check can be done.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see ActionSupport
|
||||
* @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.Validateable} instead.
|
||||
*/
|
||||
public interface Validateable {
|
||||
|
||||
/**
|
||||
* Performs validation.
|
||||
*/
|
||||
void validate();
|
||||
|
||||
@Deprecated
|
||||
public interface Validateable extends org.apache.struts2.Validateable {
|
||||
}
|
||||
|
||||
@@ -37,8 +37,16 @@ public class InterceptorMapping implements Serializable {
|
||||
private final Interceptor interceptor;
|
||||
private final Map<String, String> params;
|
||||
|
||||
public InterceptorMapping(String name, org.apache.struts2.interceptor.Interceptor interceptor) {
|
||||
this(name, Interceptor.adapt(interceptor));
|
||||
}
|
||||
|
||||
public InterceptorMapping(String name, org.apache.struts2.interceptor.Interceptor interceptor, Map<String, String> params) {
|
||||
this(name, Interceptor.adapt(interceptor), params);
|
||||
}
|
||||
|
||||
public InterceptorMapping(String name, Interceptor interceptor) {
|
||||
this(name, interceptor, new HashMap<String, String>());
|
||||
this(name, interceptor, new HashMap<>());
|
||||
}
|
||||
|
||||
public InterceptorMapping(String name, Interceptor interceptor, Map<String, String> params) {
|
||||
|
||||
@@ -70,12 +70,18 @@ public class DefaultInterceptorFactory implements InterceptorFactory {
|
||||
reflectionProvider.setProperties(params, o);
|
||||
}
|
||||
|
||||
if (o instanceof Interceptor interceptor) {
|
||||
interceptor.init();
|
||||
return interceptor;
|
||||
Interceptor interceptor = null;
|
||||
if (o instanceof Interceptor) {
|
||||
interceptor = (Interceptor) o;
|
||||
} else if (o instanceof org.apache.struts2.interceptor.Interceptor) {
|
||||
interceptor = Interceptor.adapt((org.apache.struts2.interceptor.Interceptor) o);
|
||||
}
|
||||
|
||||
throw new ConfigurationException("Class [" + interceptorClassName + "] does not implement Interceptor", interceptorConfig);
|
||||
if (interceptor == null) {
|
||||
throw new ConfigurationException("Class [" + interceptorClassName + "] does not implement Interceptor", interceptorConfig);
|
||||
}
|
||||
interceptor.init();
|
||||
return interceptor;
|
||||
} catch (InstantiationException e) {
|
||||
cause = e;
|
||||
message = "Unable to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.opensymphony.xwork2.factory;
|
||||
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionException;
|
||||
@@ -51,19 +52,29 @@ public class DefaultResultFactory implements ResultFactory {
|
||||
Result result = null;
|
||||
|
||||
if (resultClassName != null) {
|
||||
result = (Result) objectFactory.buildBean(resultClassName, extraContext);
|
||||
Object o = objectFactory.buildBean(resultClassName, extraContext);
|
||||
|
||||
Map<String, String> params = resultConfig.getParams();
|
||||
if (params != null) {
|
||||
for (Map.Entry<String, String> paramEntry : params.entrySet()) {
|
||||
try {
|
||||
reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), result, extraContext, true);
|
||||
reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), o, extraContext, true);
|
||||
} catch (ReflectionException ex) {
|
||||
if (result instanceof ReflectionExceptionHandler) {
|
||||
((ReflectionExceptionHandler) result).handle(ex);
|
||||
if (o instanceof ReflectionExceptionHandler) {
|
||||
((ReflectionExceptionHandler) o).handle(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (o instanceof Result) {
|
||||
result = (Result) o;
|
||||
} else if (o instanceof org.apache.struts2.Result) {
|
||||
result = Result.adapt((org.apache.struts2.Result) o);
|
||||
}
|
||||
if (result == null) {
|
||||
throw new ConfigurationException("Class [" + resultClassName + "] does not implement Result", resultConfig);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -21,44 +21,23 @@ package com.opensymphony.xwork2.interceptor;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* Provides default implementations of optional lifecycle methods
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.AbstractInterceptor} instead.
|
||||
*/
|
||||
public abstract class AbstractInterceptor implements ConditionalInterceptor {
|
||||
|
||||
private boolean disabled;
|
||||
|
||||
/**
|
||||
* Does nothing
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
@Deprecated
|
||||
public abstract class AbstractInterceptor extends org.apache.struts2.interceptor.AbstractInterceptor implements ConditionalInterceptor {
|
||||
|
||||
/**
|
||||
* Override to handle interception
|
||||
*/
|
||||
@Override
|
||||
public abstract String intercept(ActionInvocation invocation) throws Exception;
|
||||
|
||||
/**
|
||||
* Allows to skip executing a given interceptor, just define {@code <param name="disabled">true</param>}
|
||||
* or use other way to override interceptor's parameters, see
|
||||
* <a href="https://struts.apache.org/core-developers/interceptors#interceptor-parameter-overriding">docs</a>.
|
||||
* @param disable if set to true, execution of a given interceptor will be skipped.
|
||||
*/
|
||||
public void setDisabled(String disable) {
|
||||
this.disabled = Boolean.parseBoolean(disable);
|
||||
@Override
|
||||
public String intercept(org.apache.struts2.ActionInvocation invocation) throws Exception {
|
||||
return intercept(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIntercept(ActionInvocation invocation) {
|
||||
return !this.disabled;
|
||||
return shouldIntercept((org.apache.struts2.ActionInvocation) invocation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -90,7 +91,10 @@ import java.util.Map;
|
||||
* </pre>
|
||||
*
|
||||
* @author Matthew Payne
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.AliasInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class AliasInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(AliasInterceptor.class);
|
||||
|
||||
@@ -21,7 +21,6 @@ package com.opensymphony.xwork2.interceptor;
|
||||
import com.opensymphony.xwork2.ActionChainResult;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.Unchainable;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.ProxyUtil;
|
||||
@@ -31,6 +30,7 @@ import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.Unchainable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -118,7 +118,10 @@ import java.util.Map;
|
||||
* @author mrdon
|
||||
* @author tm_jee ( tm_jee(at)yahoo.co.uk )
|
||||
* @see com.opensymphony.xwork2.ActionChainResult
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ChainingInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ChainingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ChainingInterceptor.class);
|
||||
|
||||
+31
-11
@@ -21,19 +21,39 @@ package com.opensymphony.xwork2.interceptor;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* A marking interface, when implemented allows to conditionally execute a given interceptor
|
||||
* within the current action invocation.
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since Struts 6.1.1
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.Interceptor} instead.
|
||||
*/
|
||||
public interface ConditionalInterceptor extends Interceptor {
|
||||
@Deprecated
|
||||
public interface ConditionalInterceptor extends org.apache.struts2.interceptor.ConditionalInterceptor, Interceptor {
|
||||
|
||||
@Override
|
||||
default boolean shouldIntercept(org.apache.struts2.ActionInvocation invocation) {
|
||||
return shouldIntercept(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given interceptor should be executed in the current processing of action invocation.
|
||||
*
|
||||
* @param invocation current {@link ActionInvocation} to determine if the interceptor should be executed
|
||||
* @return true if the given interceptor should be included in the current action invocation
|
||||
* @since 6.1.1
|
||||
*/
|
||||
boolean shouldIntercept(ActionInvocation invocation);
|
||||
|
||||
static ConditionalInterceptor adapt(org.apache.struts2.interceptor.ConditionalInterceptor actualInterceptor) {
|
||||
if (actualInterceptor instanceof ConditionalInterceptor) {
|
||||
return (ConditionalInterceptor) actualInterceptor;
|
||||
}
|
||||
return actualInterceptor != null ? new LegacyAdapter(actualInterceptor) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter extends Interceptor.LegacyAdapter implements ConditionalInterceptor {
|
||||
|
||||
private final org.apache.struts2.interceptor.ConditionalInterceptor adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.interceptor.ConditionalInterceptor adaptee) {
|
||||
super(adaptee);
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIntercept(ActionInvocation invocation) {
|
||||
return adaptee.shouldIntercept(invocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -84,7 +85,10 @@ import java.util.Map;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ConversionErrorInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ConversionErrorInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
public static final String ORIGINAL_PROPERTY_OVERRIDE = "original.property.override";
|
||||
|
||||
@@ -25,6 +25,9 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
import org.apache.struts2.interceptor.ValidationErrorAware;
|
||||
import org.apache.struts2.interceptor.ValidationWorkflowAware;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
@@ -131,7 +134,10 @@ import java.io.Serial;
|
||||
* @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
|
||||
* @author Philip Luppens
|
||||
* @author tm_jee
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.DefaultWorkflowInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class DefaultWorkflowInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
@Serial
|
||||
|
||||
+3
@@ -153,7 +153,10 @@ import java.util.Map;
|
||||
*
|
||||
* @author Matthew E. Porter (matthew dot porter at metissian dot com)
|
||||
* @author Claus Ibsen
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ExceptionMappingInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class);
|
||||
|
||||
@@ -20,203 +20,56 @@ package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: introduction -->
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* An interceptor is a stateless class that follows the interceptor pattern, as
|
||||
* found in {@link jakarta.servlet.Filter} and in AOP languages.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Interceptors are objects that dynamically intercept Action invocations.
|
||||
* They provide the developer with the opportunity to define code that can be executed
|
||||
* before and/or after the execution of an action. They also have the ability
|
||||
* to prevent an action from executing. Interceptors provide developers a way to
|
||||
* encapsulate common functionality in a re-usable form that can be applied to
|
||||
* one or more Actions.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Interceptors <b>must</b> be stateless and not assume that a new instance will be created for each request or Action.
|
||||
* Interceptors may choose to either short-circuit the {@link ActionInvocation} execution and return a return code
|
||||
* (such as {@link com.opensymphony.xwork2.Action#SUCCESS}), or it may choose to do some processing before
|
||||
* and/or after delegating the rest of the procesing using {@link ActionInvocation#invoke()}.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: introduction -->
|
||||
*
|
||||
* <!-- START SNIPPET: parameterOverriding -->
|
||||
* <p>
|
||||
* Interceptor's parameter could be overridden through the following ways :-
|
||||
* </p>
|
||||
|
||||
* <b>Method 1:</b>
|
||||
* <pre>
|
||||
* <action name="myAction" class="myActionClass">
|
||||
* <interceptor-ref name="exception"/>
|
||||
* <interceptor-ref name="alias"/>
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="servletConfig"/>
|
||||
* <interceptor-ref name="prepare"/>
|
||||
* <interceptor-ref name="i18n"/>
|
||||
* <interceptor-ref name="chain"/>
|
||||
* <interceptor-ref name="modelDriven"/>
|
||||
* <interceptor-ref name="fileUpload"/>
|
||||
* <interceptor-ref name="staticParams"/>
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="conversionError"/>
|
||||
* <interceptor-ref name="validation">
|
||||
* <param name="excludeMethods">myValidationExcudeMethod</param>
|
||||
* </interceptor-ref>
|
||||
* <interceptor-ref name="workflow">
|
||||
* <param name="excludeMethods">myWorkflowExcludeMethod</param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <b>Method 2:</b>
|
||||
* <pre>
|
||||
* <action name="myAction" class="myActionClass">
|
||||
* <interceptor-ref name="defaultStack">
|
||||
* <param name="validation.excludeMethods">myValidationExcludeMethod</param>
|
||||
* <param name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* In the first method, the whole default stack is copied and the parameter then
|
||||
* changed accordingly.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* In the second method, the 'interceptor-ref' refer to an existing
|
||||
* interceptor-stack, namely defaultStack in this example, and override the validator
|
||||
* and workflow interceptor excludeMethods typically in this case. Note that in the
|
||||
* 'param' tag, the name attribute contains a dot (.) the word before the dot(.)
|
||||
* specifies the interceptor name whose parameter is to be overridden and the word after
|
||||
* the dot (.) specifies the parameter itself. Essetially it is as follows :-
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <interceptor-name>.<parameter-name>
|
||||
* </pre>
|
||||
* <p>
|
||||
* <b>Note</b> also that in this case the 'interceptor-ref' name attribute
|
||||
* is used to indicate an interceptor stack which makes sense as if it is referring
|
||||
* to the interceptor itself it would be just using Method 1 describe above.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: parameterOverriding -->
|
||||
*
|
||||
* <p>
|
||||
* <b>Nested Interceptor param overriding</b>
|
||||
* </p>
|
||||
*
|
||||
* <!-- START SNIPPET: nestedParameterOverriding -->
|
||||
* <p>
|
||||
* Interceptor stack parameter overriding could be nested into as many level as possible, though it would
|
||||
* be advisable not to nest it too deep as to avoid confusion, For example,
|
||||
* </p>
|
||||
* <pre>
|
||||
* <interceptor name="interceptor1" class="foo.bar.Interceptor1" />
|
||||
* <interceptor name="interceptor2" class="foo.bar.Interceptor2" />
|
||||
* <interceptor name="interceptor3" class="foo.bar.Interceptor3" />
|
||||
* <interceptor name="interceptor4" class="foo.bar.Interceptor4" />
|
||||
* <interceptor-stack name="stack1">
|
||||
* <interceptor-ref name="interceptor1" />
|
||||
* </interceptor-stack>
|
||||
* <interceptor-stack name="stack2">
|
||||
* <interceptor-ref name="intercetor2" />
|
||||
* <interceptor-ref name="stack1" />
|
||||
* </interceptor-stack>
|
||||
* <interceptor-stack name="stack3">
|
||||
* <interceptor-ref name="interceptor3" />
|
||||
* <interceptor-ref name="stack2" />
|
||||
* </interceptor-stack>
|
||||
* <interceptor-stack name="stack4">
|
||||
* <interceptor-ref name="interceptor4" />
|
||||
* <interceptor-ref name="stack3" />
|
||||
* </interceptor-stack>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Assuming the interceptor has the following properties
|
||||
* </p>
|
||||
*
|
||||
* <table border="1" summary="">
|
||||
* <tr>
|
||||
* <td>Interceptor</td>
|
||||
* <td>property</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor1</td>
|
||||
* <td>param1</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor2</td>
|
||||
* <td>param2</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor3</td>
|
||||
* <td>param3</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor4</td>
|
||||
* <td>param4</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>
|
||||
* We could override them as follows :
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <action ... >
|
||||
* <!-- to override parameters of interceptor located directly in the stack -->
|
||||
* <interceptor-ref name="stack4">
|
||||
* <param name="interceptor4.param4"> ... </param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
*
|
||||
* <action ... >
|
||||
* <!-- to override parameters of interceptor located under nested stack -->
|
||||
* <interceptor-ref name="stack4">
|
||||
* <param name="stack3.interceptor3.param3"> ... </param>
|
||||
* <param name="stack3.stack2.interceptor2.param2"> ... </param>
|
||||
* <param name="stack3.stack2.stack1.interceptor1.param1"> ... </param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <!-- END SNIPPET: nestedParameterOverriding -->
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @author tmjee
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.Interceptor} instead.
|
||||
*/
|
||||
public interface Interceptor extends Serializable {
|
||||
@Deprecated
|
||||
public interface Interceptor extends org.apache.struts2.interceptor.Interceptor {
|
||||
|
||||
/**
|
||||
* Called to let an interceptor clean up any resources it has allocated.
|
||||
*/
|
||||
void destroy();
|
||||
@Override
|
||||
default String intercept(org.apache.struts2.ActionInvocation invocation) throws Exception {
|
||||
return intercept(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after an interceptor is created, but before any requests are processed using
|
||||
* {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving
|
||||
* the Interceptor a chance to initialize any needed resources.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the
|
||||
* request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code.
|
||||
*
|
||||
* @param invocation the action invocation
|
||||
* @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself.
|
||||
* @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}.
|
||||
*/
|
||||
String intercept(ActionInvocation invocation) throws Exception;
|
||||
|
||||
static Interceptor adapt(org.apache.struts2.interceptor.Interceptor actualInterceptor) {
|
||||
if (actualInterceptor instanceof org.apache.struts2.interceptor.ConditionalInterceptor) {
|
||||
return ConditionalInterceptor.adapt((org.apache.struts2.interceptor.ConditionalInterceptor) actualInterceptor);
|
||||
}
|
||||
if (actualInterceptor instanceof Interceptor) {
|
||||
return (Interceptor) actualInterceptor;
|
||||
}
|
||||
return actualInterceptor != null ? new LegacyAdapter(actualInterceptor) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements Interceptor {
|
||||
|
||||
private final org.apache.struts2.interceptor.Interceptor adaptee;
|
||||
|
||||
protected LegacyAdapter(org.apache.struts2.interceptor.Interceptor adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
public org.apache.struts2.interceptor.Interceptor getAdaptee() {
|
||||
return adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
return adaptee.intercept(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
adaptee.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
adaptee.init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,10 @@ import org.apache.logging.log4j.Logger;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.LoggingInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class LoggingInterceptor extends AbstractInterceptor {
|
||||
private static final Logger LOG = LogManager.getLogger(LoggingInterceptor.class);
|
||||
private static final String FINISH_MESSAGE = "Finishing execution stack for action ";
|
||||
|
||||
+24
-21
@@ -31,56 +31,59 @@ import java.util.Set;
|
||||
*
|
||||
* <p>
|
||||
* MethodFilterInterceptor is an abstract <code>Interceptor</code> used as
|
||||
* a base class for interceptors that will filter execution based on method
|
||||
* 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:
|
||||
*
|
||||
* <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
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.MethodFilterInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(MethodFilterInterceptor.class);
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -88,7 +91,7 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
public void setIncludeMethods(String includeMethods) {
|
||||
this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods);
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getIncludeMethodsSet() {
|
||||
return includeMethods;
|
||||
}
|
||||
@@ -97,7 +100,7 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (applyInterceptor(invocation)) {
|
||||
return doIntercept(invocation);
|
||||
}
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
@@ -110,14 +113,14 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
return applyMethod;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses must override to implement the interceptor logic.
|
||||
*
|
||||
*
|
||||
* @param invocation the action invocation
|
||||
* @return the result of invocation
|
||||
* @throws Exception in case of any errors
|
||||
*/
|
||||
protected abstract String doIntercept(ActionInvocation invocation) throws Exception;
|
||||
|
||||
|
||||
}
|
||||
|
||||
+3
-121
@@ -18,127 +18,9 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.WildcardHelper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
|
||||
/**
|
||||
* Utility class contains common methods used by
|
||||
* {@link com.opensymphony.xwork2.interceptor.MethodFilterInterceptor}.
|
||||
*
|
||||
* @author tm_jee
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.MethodFilterInterceptorUtil} instead.
|
||||
*/
|
||||
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;
|
||||
for (String includeMethod : includeMethods) {
|
||||
if (!"*".equals(includeMethod) && includeMethod.contains("*")) {
|
||||
needsPatternMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (String excludeMethod : excludeMethods) {
|
||||
if (!"*".equals(excludeMethod) && excludeMethod.contains("*")) {
|
||||
needsPatternMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this section will try to honor the original logic, while
|
||||
// still allowing for wildcards later
|
||||
if (!needsPatternMatch && (includeMethods.contains("*") || includeMethods.isEmpty()) ) {
|
||||
if (excludeMethods.contains(method) && !includeMethods.contains(method)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// test the methods using pattern matching
|
||||
WildcardHelper wildcard = new WildcardHelper();
|
||||
String methodCopy ;
|
||||
// no method specified
|
||||
methodCopy = requireNonNullElse(method, "");
|
||||
for (String pattern : includeMethods) {
|
||||
if (pattern.contains("*")) {
|
||||
int[] compiledPattern = wildcard.compilePattern(pattern);
|
||||
HashMap<String, String> matchedPatterns = new HashMap<>();
|
||||
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<>();
|
||||
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.isEmpty() || 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);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public class MethodFilterInterceptorUtil extends org.apache.struts2.interceptor.MethodFilterInterceptorUtil {
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
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;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
@@ -75,7 +75,10 @@ import com.opensymphony.xwork2.util.ValueStack;
|
||||
*
|
||||
* @author tm_jee
|
||||
* @version $Date$ $Id$
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ModelDrivenInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ModelDrivenInterceptor extends AbstractInterceptor {
|
||||
|
||||
protected boolean refreshModelBeforeResult = false;
|
||||
|
||||
+3
@@ -66,7 +66,10 @@ import java.util.Set;
|
||||
* ...
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ParameterRemoverInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ParameterRemoverInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ParameterRemoverInterceptor.class);
|
||||
|
||||
@@ -21,21 +21,38 @@ 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.
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.PreResultListener} instead.
|
||||
*/
|
||||
public interface PreResultListener {
|
||||
@Deprecated
|
||||
public interface PreResultListener extends org.apache.struts2.interceptor.PreResultListener {
|
||||
|
||||
@Override
|
||||
default void beforeResult(org.apache.struts2.ActionInvocation invocation, String resultCode) {
|
||||
beforeResult(ActionInvocation.adapt(invocation), resultCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
static PreResultListener adapt(org.apache.struts2.interceptor.PreResultListener actualListener) {
|
||||
if (actualListener instanceof PreResultListener) {
|
||||
return (PreResultListener) actualListener;
|
||||
}
|
||||
return actualListener != null ? new LegacyAdapter(actualListener) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements PreResultListener {
|
||||
|
||||
private final org.apache.struts2.interceptor.PreResultListener adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.interceptor.PreResultListener adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
adaptee.beforeResult(invocation, resultCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -53,7 +53,7 @@ import java.lang.reflect.Method;
|
||||
* <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>
|
||||
* <p>
|
||||
*<p>
|
||||
* <!-- END SNIPPET: javadocPrepareInterceptor -->
|
||||
*
|
||||
* @author Philip Luppens
|
||||
@@ -129,6 +129,9 @@ public class PrefixMethodInvocationUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void invokePrefixMethod(org.apache.struts2.ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
|
||||
invokePrefixMethod(ActionInvocation.adapt(actionInvocation), prefixes);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a {@link Method} in <code>action</code>. The method
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.Preparable;
|
||||
import org.apache.struts2.Preparable;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -97,7 +97,10 @@ import java.lang.reflect.InvocationTargetException;
|
||||
* @author Philip Luppens
|
||||
* @author tm_jee
|
||||
* @see com.opensymphony.xwork2.Preparable
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.PrepareInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class PrepareInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
@Serial
|
||||
|
||||
@@ -21,23 +21,8 @@ package com.opensymphony.xwork2.interceptor;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
|
||||
/**
|
||||
* Adds the ability to set a model, probably retrieved from a given state.
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ScopedModelDriven} instead.
|
||||
*/
|
||||
public interface ScopedModelDriven<T> extends ModelDriven<T> {
|
||||
|
||||
/**
|
||||
* @param model 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);
|
||||
|
||||
/**
|
||||
* @return the key under which the model is stored
|
||||
*/
|
||||
String getScopeKey();
|
||||
@Deprecated
|
||||
public interface ScopedModelDriven<T> extends org.apache.struts2.interceptor.ScopedModelDriven<T>, ModelDriven<T> {
|
||||
}
|
||||
|
||||
+4
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.interceptor.ScopedModelDriven;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
@@ -79,7 +80,10 @@ import java.util.Map;
|
||||
*
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ScopedModelDrivenInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ScopedModelDrivenInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
|
||||
|
||||
+4
@@ -34,6 +34,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -84,7 +85,10 @@ import java.util.Map;
|
||||
* </pre>
|
||||
*
|
||||
* @author Patrick Lightbody
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.StaticParametersInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class StaticParametersInterceptor extends AbstractInterceptor {
|
||||
|
||||
private boolean parse;
|
||||
|
||||
@@ -23,109 +23,84 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ValidationAware classes can accept Action (class level) or field level error messages. Action level messages are kept
|
||||
* in a Collection. Field level error messages are kept in a Map from String field name to a List of field error msgs.
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationAware} instead.
|
||||
*/
|
||||
public interface ValidationAware {
|
||||
@Deprecated
|
||||
public interface ValidationAware extends org.apache.struts2.interceptor.ValidationAware {
|
||||
|
||||
/**
|
||||
* Set the Collection of Action-level String error messages.
|
||||
*
|
||||
* @param errorMessages Collection of String error messages
|
||||
*/
|
||||
void setActionErrors(Collection<String> errorMessages);
|
||||
|
||||
/**
|
||||
* Get the Collection of Action-level error messages for this action. Error messages should not
|
||||
* be added directly here, as implementations are free to return a new Collection or an
|
||||
* Unmodifiable Collection.
|
||||
*
|
||||
* @return Collection of String error messages
|
||||
*/
|
||||
Collection<String> getActionErrors();
|
||||
|
||||
/**
|
||||
* Set the Collection of Action-level String messages (not errors).
|
||||
*
|
||||
* @param messages Collection of String messages (not errors).
|
||||
*/
|
||||
void setActionMessages(Collection<String> messages);
|
||||
|
||||
/**
|
||||
* Get the Collection of Action-level messages for this action. Messages should not be added
|
||||
* directly here, as implementations are free to return a new Collection or an Unmodifiable
|
||||
* Collection.
|
||||
*
|
||||
* @return Collection of String messages
|
||||
*/
|
||||
Collection<String> getActionMessages();
|
||||
|
||||
/**
|
||||
* Set the field error map of fieldname (String) to Collection of String error messages.
|
||||
*
|
||||
* @param errorMap field error map
|
||||
*/
|
||||
void setFieldErrors(Map<String, List<String>> errorMap);
|
||||
|
||||
/**
|
||||
* Get the field specific errors associated with this action. Error messages should not be added
|
||||
* directly here, as implementations are free to return a new Collection or an Unmodifiable
|
||||
* Collection.
|
||||
*
|
||||
* @return Map with errors mapped from fieldname (String) to Collection of String error messages
|
||||
*/
|
||||
Map<String, List<String>> getFieldErrors();
|
||||
|
||||
/**
|
||||
* Add an Action-level error message to this Action.
|
||||
*
|
||||
* @param anErrorMessage the error message
|
||||
*/
|
||||
void addActionError(String anErrorMessage);
|
||||
|
||||
/**
|
||||
* Add an Action-level message to this Action.
|
||||
*
|
||||
* @param aMessage the message
|
||||
*/
|
||||
void addActionMessage(String aMessage);
|
||||
|
||||
/**
|
||||
* Add an error message for a given field.
|
||||
*
|
||||
* @param fieldName name of field
|
||||
* @param errorMessage the error message
|
||||
*/
|
||||
void addFieldError(String fieldName, String errorMessage);
|
||||
|
||||
/**
|
||||
* Check whether there are any Action-level error messages.
|
||||
*
|
||||
* @return true if any Action-level error messages have been registered
|
||||
*/
|
||||
boolean hasActionErrors();
|
||||
|
||||
/**
|
||||
* Checks whether there are any Action-level messages.
|
||||
*
|
||||
* @return true if any Action-level messages have been registered
|
||||
*/
|
||||
boolean hasActionMessages();
|
||||
|
||||
/**
|
||||
* Checks whether there are any action errors or field errors.
|
||||
*
|
||||
* @return <code>(hasActionErrors() || hasFieldErrors())</code>
|
||||
*/
|
||||
default boolean hasErrors() {
|
||||
return hasActionErrors() || hasFieldErrors();
|
||||
static ValidationAware adapt(org.apache.struts2.interceptor.ValidationAware actualValidation) {
|
||||
if (actualValidation instanceof ValidationAware) {
|
||||
return (ValidationAware) actualValidation;
|
||||
}
|
||||
return actualValidation != null ? new LegacyAdapter(actualValidation) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there are any field errors associated with this action.
|
||||
*
|
||||
* @return whether there are any field errors
|
||||
*/
|
||||
boolean hasFieldErrors();
|
||||
class LegacyAdapter implements ValidationAware {
|
||||
|
||||
private final org.apache.struts2.interceptor.ValidationAware adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.interceptor.ValidationAware adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionErrors(Collection<String> errorMessages) {
|
||||
adaptee.setActionErrors(errorMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionErrors() {
|
||||
return adaptee.getActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionMessages(Collection<String> messages) {
|
||||
adaptee.setActionMessages(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionMessages() {
|
||||
return adaptee.getActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFieldErrors(Map<String, List<String>> errorMap) {
|
||||
adaptee.setFieldErrors(errorMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getFieldErrors() {
|
||||
return adaptee.getFieldErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionError(String anErrorMessage) {
|
||||
adaptee.addActionError(anErrorMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionMessage(String aMessage) {
|
||||
adaptee.addActionMessage(aMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFieldError(String fieldName, String errorMessage) {
|
||||
adaptee.addFieldError(fieldName, errorMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionErrors() {
|
||||
return adaptee.hasActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionMessages() {
|
||||
return adaptee.hasActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFieldErrors() {
|
||||
return adaptee.hasFieldErrors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,22 +19,8 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
/**
|
||||
* ValidationErrorAware classes can be notified about validation errors
|
||||
* before {@link com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor} will return 'inputResultName' result
|
||||
* to allow change or not the result name
|
||||
*
|
||||
* This interface can be only applied to action which already implements {@link ValidationAware} interface!
|
||||
*
|
||||
* @since 2.3.15
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationErrorAware} instead.
|
||||
*/
|
||||
public interface ValidationErrorAware {
|
||||
|
||||
/**
|
||||
* Allows to notify action about occurred action/field errors
|
||||
*
|
||||
* @param currentResultName current result name, action can change it or return the same
|
||||
* @return new result name or passed currentResultName
|
||||
*/
|
||||
String actionErrorOccurred(final String currentResultName);
|
||||
|
||||
@Deprecated
|
||||
public interface ValidationErrorAware extends org.apache.struts2.interceptor.ValidationErrorAware {
|
||||
}
|
||||
|
||||
@@ -19,12 +19,8 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
/**
|
||||
* ValidationWorkflowAware classes can programmatically change result name when errors occurred
|
||||
*
|
||||
* This interface can be only applied to action which already implements {@link ValidationAware} interface!
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationWorkflowAware} instead.
|
||||
*/
|
||||
public interface ValidationWorkflowAware {
|
||||
|
||||
String getInputResultName();
|
||||
|
||||
@Deprecated
|
||||
public interface ValidationWorkflowAware extends org.apache.struts2.interceptor.ValidationWorkflowAware {
|
||||
}
|
||||
|
||||
@@ -67,11 +67,14 @@ public interface WithLazyParams {
|
||||
}
|
||||
|
||||
public Interceptor injectParams(Interceptor interceptor, Map<String, String> params, ActionContext invocationContext) {
|
||||
return (Interceptor) injectParams((org.apache.struts2.interceptor.Interceptor) interceptor, params, invocationContext);
|
||||
}
|
||||
|
||||
public org.apache.struts2.interceptor.Interceptor injectParams(org.apache.struts2.interceptor.Interceptor interceptor, Map<String, String> params, ActionContext invocationContext) {
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
Object paramValue = textParser.evaluate(new char[]{ '$' }, entry.getValue(), valueEvaluator, TextParser.DEFAULT_LOOP_COUNT);
|
||||
ognlUtil.setProperty(entry.getKey(), paramValue, interceptor, invocationContext.getContextMap());
|
||||
}
|
||||
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
package com.opensymphony.xwork2.util;
|
||||
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -20,12 +20,12 @@ package com.opensymphony.xwork2.util;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -23,144 +23,127 @@ import com.opensymphony.xwork2.ActionContext;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ValueStack allows multiple beans to be pushed in and dynamic EL expressions to be evaluated against it. When
|
||||
* evaluating an expression, the stack will be searched down the stack, from the latest objects pushed in to the
|
||||
* earliest, looking for a bean with a getter or setter for the given property or a method of the given name (depending
|
||||
* on the expression being evaluated).
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.util.ValueStack} instead.
|
||||
*/
|
||||
public interface ValueStack {
|
||||
|
||||
String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
|
||||
|
||||
String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp";
|
||||
|
||||
/**
|
||||
* Gets the context for this value stack. The context holds all the information in the value stack and it's surroundings.
|
||||
*
|
||||
* @return the context.
|
||||
*/
|
||||
Map<String, Object> getContext();
|
||||
@Deprecated
|
||||
public interface ValueStack extends org.apache.struts2.util.ValueStack {
|
||||
|
||||
@Override
|
||||
ActionContext getActionContext();
|
||||
|
||||
/**
|
||||
* Sets the default type to convert to if no type is provided when getting a value.
|
||||
*
|
||||
* @param defaultType the new default type
|
||||
*/
|
||||
void setDefaultType(Class defaultType);
|
||||
static ValueStack adapt(org.apache.struts2.util.ValueStack actualStack) {
|
||||
if (actualStack instanceof ValueStack) {
|
||||
return (ValueStack) actualStack;
|
||||
}
|
||||
return actualStack != null ? new LegacyAdapter(actualStack) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a override map containing <code> key -> values </code> that takes precedent when doing find operations on the ValueStack.
|
||||
* <p>
|
||||
* See the unit test for ValueStackTest for examples.
|
||||
* </p>
|
||||
*
|
||||
* @param overrides overrides map.
|
||||
*/
|
||||
void setExprOverrides(Map<Object, Object> overrides);
|
||||
class LegacyAdapter implements ValueStack {
|
||||
|
||||
/**
|
||||
* Gets the override map if anyone exists.
|
||||
*
|
||||
* @return the override map, <tt>null</tt> if not set.
|
||||
*/
|
||||
Map<Object, Object> getExprOverrides();
|
||||
private final org.apache.struts2.util.ValueStack adaptee;
|
||||
|
||||
/**
|
||||
* Get the CompoundRoot which holds the objects pushed onto the stack
|
||||
*
|
||||
* @return the root
|
||||
*/
|
||||
CompoundRoot getRoot();
|
||||
private LegacyAdapter(org.apache.struts2.util.ValueStack adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to set a property on a bean in the stack with the given expression using the default search order.
|
||||
*
|
||||
* @param expr the expression defining the path to the property to be set.
|
||||
* @param value the value to be set into the named property
|
||||
*/
|
||||
void setValue(String expr, Object value);
|
||||
@Override
|
||||
public Map<String, Object> getContext() {
|
||||
return adaptee.getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to set a property on a bean in the stack with the given expression using the default search order.
|
||||
* N.B.: unlike #setValue(String,Object) it doesn't allow eval expression.
|
||||
* @param expr the expression defining the path to the property to be set.
|
||||
* @param value the value to be set into the named property
|
||||
*/
|
||||
void setParameter(String expr, Object value);
|
||||
@Override
|
||||
public ActionContext getActionContext() {
|
||||
return ActionContext.adapt(adaptee.getActionContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to set a property on a bean in the stack with the given expression using the default search order.
|
||||
*
|
||||
* @param expr the expression defining the path to the property to be set.
|
||||
* @param value the value to be set into the named property
|
||||
* @param throwExceptionOnFailure a flag to tell whether an exception should be thrown if there is no property with
|
||||
* the given name.
|
||||
*/
|
||||
void setValue(String expr, Object value, boolean throwExceptionOnFailure);
|
||||
@Override
|
||||
public void setDefaultType(Class defaultType) {
|
||||
adaptee.setDefaultType(defaultType);
|
||||
}
|
||||
|
||||
String findString(String expr);
|
||||
String findString(String expr, boolean throwExceptionOnFailure);
|
||||
@Override
|
||||
public void setExprOverrides(Map<Object, Object> overrides) {
|
||||
adaptee.setExprOverrides(overrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a value by evaluating the given expression against the stack in the default search order.
|
||||
*
|
||||
* @param expr the expression giving the path of properties to navigate to find the property value to return
|
||||
* @return the result of evaluating the expression
|
||||
*/
|
||||
Object findValue(String expr);
|
||||
@Override
|
||||
public Map<Object, Object> getExprOverrides() {
|
||||
return adaptee.getExprOverrides();
|
||||
}
|
||||
|
||||
Object findValue(String expr, boolean throwExceptionOnFailure);
|
||||
@Override
|
||||
public CompoundRoot getRoot() {
|
||||
return adaptee.getRoot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a value by evaluating the given expression against the stack in the default search order.
|
||||
*
|
||||
* @param expr the expression giving the path of properties to navigate to find the property value to return
|
||||
* @param asType the type to convert the return value to
|
||||
* @return the result of evaluating the expression
|
||||
*/
|
||||
Object findValue(String expr, Class asType);
|
||||
Object findValue(String expr, Class asType, boolean throwExceptionOnFailure);
|
||||
@Override
|
||||
public void setValue(String expr, Object value) {
|
||||
adaptee.setValue(expr, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object on the top of the stack <b>without</b> changing the stack.
|
||||
*
|
||||
* @return the object on the top.
|
||||
* @see CompoundRoot#peek()
|
||||
*/
|
||||
Object peek();
|
||||
@Override
|
||||
public void setParameter(String expr, Object value) {
|
||||
adaptee.setParameter(expr, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object on the top of the stack and <b>remove</b> it from the stack.
|
||||
*
|
||||
* @return the object on the top of the stack
|
||||
* @see CompoundRoot#pop()
|
||||
*/
|
||||
Object pop();
|
||||
@Override
|
||||
public void setValue(String expr, Object value, boolean throwExceptionOnFailure) {
|
||||
adaptee.setValue(expr, value, throwExceptionOnFailure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put this object onto the top of the stack
|
||||
*
|
||||
* @param o the object to be pushed onto the stack
|
||||
* @see CompoundRoot#push(Object)
|
||||
*/
|
||||
void push(Object o);
|
||||
@Override
|
||||
public String findString(String expr) {
|
||||
return adaptee.findString(expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an object on the stack with the given key
|
||||
* so it is retrievable by {@link #findValue(String)}, {@link #findValue(String, Class)}
|
||||
*
|
||||
* @param key the key
|
||||
* @param o the object
|
||||
*/
|
||||
void set(String key, Object o);
|
||||
@Override
|
||||
public String findString(String expr, boolean throwExceptionOnFailure) {
|
||||
return adaptee.findString(expr, throwExceptionOnFailure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of objects in the stack
|
||||
*
|
||||
* @return the number of objects in the stack
|
||||
*/
|
||||
int size();
|
||||
@Override
|
||||
public Object findValue(String expr) {
|
||||
return adaptee.findValue(expr);
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public Object findValue(String expr, boolean throwExceptionOnFailure) {
|
||||
return adaptee.findValue(expr, throwExceptionOnFailure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object findValue(String expr, Class asType) {
|
||||
return adaptee.findValue(expr, asType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object findValue(String expr, Class asType, boolean throwExceptionOnFailure) {
|
||||
return adaptee.findValue(expr, asType, throwExceptionOnFailure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object peek() {
|
||||
return adaptee.peek();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object pop() {
|
||||
return adaptee.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(Object o) {
|
||||
adaptee.push(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, Object o) {
|
||||
adaptee.set(key, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return adaptee.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -254,8 +254,8 @@ public class DelegatingValidatorContext implements ValidatorContext {
|
||||
}
|
||||
|
||||
protected static ValidationAware makeValidationAware(Object object) {
|
||||
if (object instanceof ValidationAware) {
|
||||
return (ValidationAware) object;
|
||||
if (object instanceof org.apache.struts2.interceptor.ValidationAware) {
|
||||
return ValidationAware.adapt((org.apache.struts2.interceptor.ValidationAware) object);
|
||||
} else {
|
||||
return new LoggingValidationAware(object);
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ package com.opensymphony.xwork2.validator;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.Validateable;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.PrefixMethodInvocationUtil;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.Validateable;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
@@ -71,9 +71,9 @@ import org.apache.logging.log4j.Logger;
|
||||
* <li>programmatic - Defaults to true. If true and the action is Validateable call validate(),
|
||||
* and any method that starts with "validate".
|
||||
* </li>
|
||||
*
|
||||
*
|
||||
* <li>declarative - Defaults to true. Perform validation based on xml or annotations.</li>
|
||||
*
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
@@ -90,14 +90,14 @@ import org.apache.logging.log4j.Logger;
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
*
|
||||
*
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="validation"/>
|
||||
* <interceptor-ref name="workflow"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
*
|
||||
*
|
||||
* <-- in the following case myMethod of the action class will not
|
||||
* get validated -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
@@ -108,7 +108,7 @@ import org.apache.logging.log4j.Logger;
|
||||
* <interceptor-ref name="workflow"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
*
|
||||
*
|
||||
* <-- in the following case only annotated methods of the action class will
|
||||
* be validated -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
@@ -138,9 +138,9 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
private final static String ALT_VALIDATE_PREFIX = "validateDo";
|
||||
|
||||
private boolean validateAnnotatedMethodOnly;
|
||||
|
||||
|
||||
private ActionValidatorManager actionValidatorManager;
|
||||
|
||||
|
||||
private boolean alwaysInvokeValidate = true;
|
||||
private boolean programmatic = true;
|
||||
private boolean declarative = true;
|
||||
@@ -149,11 +149,11 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
public void setActionValidatorManager(ActionValidatorManager mgr) {
|
||||
this.actionValidatorManager = mgr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if {@link Validateable}'s <code>validate()</code> should be called,
|
||||
* as well as methods whose name that start with "validate". Defaults to "true".
|
||||
*
|
||||
*
|
||||
* @param programmatic <tt>true</tt> then <code>validate()</code> is invoked.
|
||||
*/
|
||||
public void setProgrammatic(boolean programmatic) {
|
||||
@@ -161,9 +161,9 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if validation based on annotations or xml should be performed. Defaults
|
||||
* Determines if validation based on annotations or xml should be performed. Defaults
|
||||
* to "true".
|
||||
*
|
||||
*
|
||||
* @param declarative <tt>true</tt> then perform validation based on annotations or xml.
|
||||
*/
|
||||
public void setDeclarative(boolean declarative) {
|
||||
@@ -171,9 +171,9 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if {@link Validateable}'s <code>validate()</code> should always
|
||||
* Determines if {@link Validateable}'s <code>validate()</code> should always
|
||||
* be invoked. Default to "true".
|
||||
*
|
||||
*
|
||||
* @param alwaysInvokeValidate <tt>true</tt> then <code>validate()</code> is always invoked.
|
||||
*/
|
||||
public void setAlwaysInvokeValidate(String alwaysInvokeValidate) {
|
||||
@@ -218,7 +218,7 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Validating {}/{} with method {}.", invocation.getProxy().getNamespace(), invocation.getProxy().getActionName(), method);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (declarative) {
|
||||
if (validateAnnotatedMethodOnly) {
|
||||
@@ -226,12 +226,12 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
} else {
|
||||
actionValidatorManager.validate(action, context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (action instanceof Validateable && programmatic) {
|
||||
// keep exception that might occured in validateXXX or validateDoXXX
|
||||
Exception exception = null;
|
||||
|
||||
Exception exception = null;
|
||||
|
||||
Validateable validateable = (Validateable) action;
|
||||
LOG.debug("Invoking validate() on action {}", validateable);
|
||||
|
||||
@@ -239,19 +239,19 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
PrefixMethodInvocationUtil.invokePrefixMethod(invocation, new String[]{VALIDATE_PREFIX, ALT_VALIDATE_PREFIX});
|
||||
}
|
||||
catch(Exception e) {
|
||||
// If any exception occurred while doing reflection, we want
|
||||
// If any exception occurred while doing reflection, we want
|
||||
// validate() to be executed
|
||||
LOG.warn("an exception occured while executing the prefix method", e);
|
||||
exception = e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (alwaysInvokeValidate) {
|
||||
validateable.validate();
|
||||
}
|
||||
|
||||
if (exception != null) {
|
||||
// rethrow if something is wrong while doing validateXXX / validateDoXXX
|
||||
|
||||
if (exception != null) {
|
||||
// rethrow if something is wrong while doing validateXXX / validateDoXXX
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
@@ -262,7 +262,7 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
doBeforeInvocation(invocation);
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the context that will be used by the
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
/**
|
||||
* All actions <b>may</b> implement this interface, which exposes the <code>execute()</code> method.
|
||||
* <p>
|
||||
* However, as of XWork 1.1, this is <b>not</b> required and is only here to assist users. You are free to create POJOs
|
||||
* that honor the same contract defined by this interface without actually implementing the interface.
|
||||
* </p>
|
||||
*/
|
||||
public interface Action {
|
||||
|
||||
/**
|
||||
* The action execution was successful. Show result
|
||||
* view to the end user.
|
||||
*/
|
||||
String SUCCESS = "success";
|
||||
|
||||
/**
|
||||
* The action execution was successful but do not
|
||||
* show a view. This is useful for actions that are
|
||||
* handling the view in another fashion like redirect.
|
||||
*/
|
||||
String NONE = "none";
|
||||
|
||||
/**
|
||||
* The action execution was a failure.
|
||||
* Show an error view, possibly asking the
|
||||
* user to retry entering data.
|
||||
*/
|
||||
String ERROR = "error";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The action execution require more input
|
||||
* in order to succeed.
|
||||
* This result is typically used if a form
|
||||
* handling action has been executed so as
|
||||
* to provide defaults for a form. The
|
||||
* form associated with the handler should be
|
||||
* shown to the end user.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This result is also used if the given input
|
||||
* params are invalid, meaning the user
|
||||
* should try providing input again.
|
||||
* </p>
|
||||
*/
|
||||
String INPUT = "input";
|
||||
|
||||
/**
|
||||
* The action could not execute, since the
|
||||
* user most was not logged in. The login view
|
||||
* should be shown.
|
||||
*/
|
||||
String LOGIN = "login";
|
||||
|
||||
|
||||
/**
|
||||
* Where the logic of the action is executed.
|
||||
*
|
||||
* @return a string representing the logical result of the execution.
|
||||
* See constants in this interface for a list of standard result values.
|
||||
* @throws Exception thrown if a system level exception occurs.
|
||||
* <b>Note:</b> Application level exceptions should be handled by returning
|
||||
* an error value, such as <code>Action.ERROR</code>.
|
||||
*/
|
||||
String execute() throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.jsp.PageContext;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The ActionContext is the context in which an {@link Action} is executed. Each context is basically a
|
||||
* container of objects an action needs for execution like the session, parameters, locale, etc.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The ActionContext is thread local which means that values stored in the ActionContext are
|
||||
* unique per thread. See the {@link ThreadLocal} class for more information. The benefit of
|
||||
* this is you don't need to worry about a user specific action context, you just get it:
|
||||
* </p>
|
||||
*
|
||||
* <code>ActionContext context = ActionContext.getContext();</code>
|
||||
*
|
||||
* <p>
|
||||
* Finally, because of the thread local usage you don't need to worry about making your actions thread safe.
|
||||
* </p>
|
||||
*
|
||||
* @author Patrick Lightbody
|
||||
* @author Bill Lynch (docs)
|
||||
*/
|
||||
public class ActionContext implements Serializable {
|
||||
|
||||
private static final ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Constant for the name of the action being executed.
|
||||
*/
|
||||
private static final String ACTION_NAME = "org.apache.struts2.ActionContext.name";
|
||||
|
||||
/**
|
||||
* Constant for the {@link ValueStack OGNL value stack}.
|
||||
*/
|
||||
private static final String VALUE_STACK = ValueStack.VALUE_STACK;
|
||||
|
||||
/**
|
||||
* Constant for the action's session.
|
||||
*/
|
||||
private static final String SESSION = "org.apache.struts2.ActionContext.session";
|
||||
|
||||
/**
|
||||
* Constant for the action's application context.
|
||||
*/
|
||||
private static final String APPLICATION = "org.apache.struts2.ActionContext.application";
|
||||
|
||||
/**
|
||||
* Constant for the action's parameters.
|
||||
*/
|
||||
private static final String PARAMETERS = "org.apache.struts2.ActionContext.parameters";
|
||||
|
||||
/**
|
||||
* Constant for the action's locale.
|
||||
*/
|
||||
private static final String LOCALE = "org.apache.struts2.ActionContext.locale";
|
||||
|
||||
/**
|
||||
* Constant for the action's {@link ActionInvocation invocation} context.
|
||||
*/
|
||||
private static final String ACTION_INVOCATION = "org.apache.struts2.ActionContext.actionInvocation";
|
||||
|
||||
/**
|
||||
* Constant for the map of type conversion errors.
|
||||
*/
|
||||
private static final String CONVERSION_ERRORS = "org.apache.struts2.ActionContext.conversionErrors";
|
||||
|
||||
/**
|
||||
* Constant for the container
|
||||
*/
|
||||
private static final String CONTAINER = "org.apache.struts2.ActionContext.container";
|
||||
|
||||
private final Map<String, Object> context;
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext initialized with another context.
|
||||
*
|
||||
* @param context a context map.
|
||||
*/
|
||||
protected ActionContext(Map<String, Object> context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on passed in Map
|
||||
*
|
||||
* @param context a map with context values
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of(Map<String, Object> context) {
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("Context cannot be null!");
|
||||
}
|
||||
return new ActionContext(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on empty Map
|
||||
*
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of() {
|
||||
return of(new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the provided context with the current thread
|
||||
*
|
||||
* @param actionContext context to bind to the thread
|
||||
* @return context which was bound to the thread
|
||||
*/
|
||||
public static ActionContext bind(ActionContext actionContext) {
|
||||
ActionContext.setContext(actionContext);
|
||||
return ActionContext.getContext();
|
||||
}
|
||||
|
||||
public static boolean containsValueStack(Map<String, Object> context) {
|
||||
return context != null && context.containsKey(VALUE_STACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds this context with the current thread
|
||||
*
|
||||
* @return this context which was bound to the thread
|
||||
*/
|
||||
public ActionContext bind() {
|
||||
ActionContext.setContext(this);
|
||||
return ActionContext.getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipes out current ActionContext, use wisely!
|
||||
*/
|
||||
public static void clear() {
|
||||
actionContext.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action context for the current thread.
|
||||
*
|
||||
* @param context the action context.
|
||||
*/
|
||||
private static void setContext(ActionContext context) {
|
||||
actionContext.set(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ActionContext specific to the current thread.
|
||||
*
|
||||
* @return the ActionContext for the current thread, is never <tt>null</tt>.
|
||||
*/
|
||||
public static ActionContext getContext() {
|
||||
return actionContext.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action invocation (the execution state).
|
||||
*
|
||||
* @param actionInvocation the action execution state.
|
||||
*/
|
||||
public ActionContext withActionInvocation(ActionInvocation actionInvocation) {
|
||||
put(ACTION_INVOCATION, actionInvocation);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the action invocation (the execution state).
|
||||
*
|
||||
* @return the action invocation (the execution state).
|
||||
*/
|
||||
public ActionInvocation getActionInvocation() {
|
||||
return (ActionInvocation) get(ACTION_INVOCATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action's application context.
|
||||
*
|
||||
* @param application the action's application context.
|
||||
*/
|
||||
public ActionContext withApplication(Map<String, Object> application) {
|
||||
put(APPLICATION, application);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of the ServletContext when in a servlet environment or a generic application level Map otherwise.
|
||||
*
|
||||
* @return a Map of ServletContext or generic application level Map
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getApplication() {
|
||||
return (Map<String, Object>) get(APPLICATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context map.
|
||||
*
|
||||
* @return the context map.
|
||||
*/
|
||||
public Map<String, Object> getContextMap() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @param conversionErrors a Map of errors which occurred when executing the action.
|
||||
*/
|
||||
public ActionContext withConversionErrors(Map<String, ConversionData> conversionErrors) {
|
||||
put(CONVERSION_ERRORS, conversionErrors);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the map of conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @return the map of conversion errors which occurred when executing the action or an empty map if
|
||||
* there were no errors.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, ConversionData> getConversionErrors() {
|
||||
Map<String, ConversionData> errors = (Map<String, ConversionData>) get(CONVERSION_ERRORS);
|
||||
|
||||
if (errors == null) {
|
||||
errors = withConversionErrors(new HashMap<>()).getConversionErrors();
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Locale for the current action.
|
||||
*
|
||||
* @param locale the Locale for the current action.
|
||||
*/
|
||||
public ActionContext withLocale(Locale locale) {
|
||||
put(LOCALE, locale);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Locale of the current action. If no locale was ever specified the platform's
|
||||
* {@link Locale#getDefault() default locale} is used.
|
||||
*
|
||||
* @return the Locale of the current action.
|
||||
*/
|
||||
public Locale getLocale() {
|
||||
Locale locale = (Locale) get(LOCALE);
|
||||
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
withLocale(locale);
|
||||
}
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the current Action in the ActionContext.
|
||||
*
|
||||
* @param actionName the name of the current action.
|
||||
*/
|
||||
public ActionContext withActionName(String actionName) {
|
||||
put(ACTION_NAME, actionName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the current Action.
|
||||
*
|
||||
* @return the name of the current action.
|
||||
*/
|
||||
public String getActionName() {
|
||||
return (String) get(ACTION_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action parameters.
|
||||
*
|
||||
* @param parameters the parameters for the current action.
|
||||
*/
|
||||
public ActionContext withParameters(HttpParameters parameters) {
|
||||
put(PARAMETERS, parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of the HttpServletRequest parameters when in a servlet environment or a generic Map of
|
||||
* parameters otherwise.
|
||||
*
|
||||
* @return a Map of HttpServletRequest parameters or a multipart map when in a servlet environment, or a
|
||||
* generic Map of parameters otherwise.
|
||||
*/
|
||||
public HttpParameters getParameters() {
|
||||
return (HttpParameters) get(PARAMETERS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of action session values.
|
||||
*
|
||||
* @param session the session values.
|
||||
*/
|
||||
public ActionContext withSession(Map<String, Object> session) {
|
||||
put(SESSION, session);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
|
||||
*
|
||||
* @return the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getSession() {
|
||||
return (Map<String, Object>) get(SESSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OGNL value stack.
|
||||
*
|
||||
* @param valueStack the OGNL value stack.
|
||||
*/
|
||||
public ActionContext withValueStack(ValueStack valueStack) {
|
||||
put(VALUE_STACK, valueStack);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OGNL value stack.
|
||||
*
|
||||
* @return the OGNL value stack.
|
||||
*/
|
||||
public ValueStack getValueStack() {
|
||||
return (ValueStack) get(VALUE_STACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the container for this request
|
||||
*
|
||||
* @param container The container
|
||||
*/
|
||||
public ActionContext withContainer(Container container) {
|
||||
put(CONTAINER, container);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the container for this request
|
||||
*
|
||||
* @return The container
|
||||
*/
|
||||
public Container getContainer() {
|
||||
return (Container) get(CONTAINER);
|
||||
}
|
||||
|
||||
public <T> T getInstance(Class<T> type) {
|
||||
Container cont = getContainer();
|
||||
if (cont != null) {
|
||||
return cont.getInstance(type);
|
||||
} else {
|
||||
throw new StrutsException("Cannot find an initialized container for this request.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.
|
||||
*
|
||||
* @param key the key used to find the value.
|
||||
* @return the value that was found using the key or <tt>null</tt> if the key was not found.
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return context.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value in the current ActionContext. The value can be looked up using the key.
|
||||
*
|
||||
* @param key the key of the value.
|
||||
* @param value the value to be stored.
|
||||
*/
|
||||
public void put(String key, Object value) {
|
||||
context.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletContext associated with current action
|
||||
*
|
||||
* @return current ServletContext
|
||||
*/
|
||||
public ServletContext getServletContext() {
|
||||
return (ServletContext) get(StrutsStatics.SERVLET_CONTEXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletContext to action context
|
||||
*
|
||||
* @param servletContext associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withServletContext(ServletContext servletContext) {
|
||||
put(StrutsStatics.SERVLET_CONTEXT, servletContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletRequest associated with current action
|
||||
*
|
||||
* @return current ServletRequest
|
||||
*/
|
||||
public HttpServletRequest getServletRequest() {
|
||||
return (HttpServletRequest) get(StrutsStatics.HTTP_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletRequest to action context
|
||||
*
|
||||
* @param request associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withServletRequest(HttpServletRequest request) {
|
||||
put(StrutsStatics.HTTP_REQUEST, request);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletResponse associated with current action
|
||||
*
|
||||
* @return current ServletResponse
|
||||
*/
|
||||
public HttpServletResponse getServletResponse() {
|
||||
return (HttpServletResponse) get(StrutsStatics.HTTP_RESPONSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletResponse to action context
|
||||
*
|
||||
* @param response associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withServletResponse(HttpServletResponse response) {
|
||||
put(StrutsStatics.HTTP_RESPONSE, response);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets PageContext associated with current action
|
||||
*
|
||||
* @return current PageContext
|
||||
*/
|
||||
public PageContext getPageContext() {
|
||||
return (PageContext) get(StrutsStatics.PAGE_CONTEXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns PageContext to action context
|
||||
*
|
||||
* @param pageContext associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withPageContext(PageContext pageContext) {
|
||||
put(StrutsStatics.PAGE_CONTEXT, pageContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ActionMapping associated with current action
|
||||
*
|
||||
* @return current ActionMapping
|
||||
*/
|
||||
public ActionMapping getActionMapping() {
|
||||
return (ActionMapping) get(StrutsStatics.ACTION_MAPPING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ActionMapping to action context
|
||||
*
|
||||
* @param actionMapping associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withActionMapping(ActionMapping actionMapping) {
|
||||
put(StrutsStatics.ACTION_MAPPING, actionMapping);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns an extra context map to action context
|
||||
*
|
||||
* @param extraContext to add to the current action context
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withExtraContext(Map<String, Object> extraContext) {
|
||||
if (extraContext != null) {
|
||||
context.putAll(extraContext);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds arbitrary key to action context
|
||||
*
|
||||
* @param key a string
|
||||
* @param value an object
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext with(String key, Object value) {
|
||||
put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ActionContext)) {
|
||||
return false;
|
||||
}
|
||||
ActionContext other = (ActionContext) obj;
|
||||
return Objects.equals(getContextMap(), other.getContextMap());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
/**
|
||||
* Provides hooks for handling key action events
|
||||
*/
|
||||
public interface ActionEventListener {
|
||||
/**
|
||||
* Called after an action has been created.
|
||||
*
|
||||
* @param action The action
|
||||
* @param stack The current value stack
|
||||
* @return The action to use
|
||||
*/
|
||||
Object prepare(Object action, ValueStack stack);
|
||||
|
||||
/**
|
||||
* Called when an exception is thrown by the action
|
||||
*
|
||||
* @param t The exception/error that was thrown
|
||||
* @param stack The current value stack
|
||||
* @return A result code to execute, can be null
|
||||
*/
|
||||
String handleException(Throwable t, ValueStack stack);
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
import com.opensymphony.xwork2.ActionChainResult;
|
||||
import org.apache.struts2.interceptor.PreResultListener;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
/**
|
||||
* An {@link ActionInvocation} represents the execution state of an {@link Action}. It holds the Interceptors and the Action instance.
|
||||
* By repeated re-entrant execution of the <code>invoke()</code> method, initially by the {@link ActionProxy}, then by the Interceptors, the
|
||||
* Interceptors are all executed, and then the {@link Action} and the {@link Result}.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see ActionProxy
|
||||
*/
|
||||
public interface ActionInvocation {
|
||||
|
||||
/**
|
||||
* Get the Action associated with this ActionInvocation.
|
||||
*
|
||||
* @return the Action
|
||||
*/
|
||||
Object getAction();
|
||||
|
||||
/**
|
||||
* Gets whether this ActionInvocation has executed before.
|
||||
* This will be set after the Action and the Result have executed.
|
||||
*
|
||||
* @return <tt>true</tt> if this ActionInvocation has executed before.
|
||||
*/
|
||||
boolean isExecuted();
|
||||
|
||||
/**
|
||||
* Gets the ActionContext associated with this ActionInvocation. The ActionProxy is
|
||||
* responsible for setting this ActionContext onto the ThreadLocal before invoking
|
||||
* the ActionInvocation and resetting the old ActionContext afterwards.
|
||||
*
|
||||
* @return the ActionContext.
|
||||
*/
|
||||
ActionContext getInvocationContext();
|
||||
|
||||
/**
|
||||
* Get the ActionProxy holding this ActionInvocation.
|
||||
*
|
||||
* @return the ActionProxy.
|
||||
*/
|
||||
ActionProxy getProxy();
|
||||
|
||||
/**
|
||||
* If the ActionInvocation has been executed before and the Result is an instance of {@link ActionChainResult}, this method
|
||||
* will walk down the chain of <code>ActionChainResult</code>s until it finds a non-chain result, which will be returned. If the
|
||||
* ActionInvocation's result has not been executed before, the Result instance will be created and populated with
|
||||
* the result params.
|
||||
*
|
||||
* @return the result.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
Result getResult() throws Exception;
|
||||
|
||||
/**
|
||||
* Gets the result code returned from this ActionInvocation.
|
||||
*
|
||||
* @return the result code
|
||||
*/
|
||||
String getResultCode();
|
||||
|
||||
/**
|
||||
* Sets the result code, possibly overriding the one returned by the
|
||||
* action.
|
||||
*
|
||||
* <p>
|
||||
* The "intended" purpose of this method is to allow PreResultListeners to
|
||||
* override the result code returned by the Action.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is used before the Action executes, the Action's returned
|
||||
* result code will override what was set. However the Action could (if
|
||||
* specifically coded to do so) inspect the ActionInvocation to see that
|
||||
* someone "upstream" (e.g. an Interceptor) had suggested a value as the
|
||||
* result, and it could therefore return the same value itself.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is called between the Action execution and the Result
|
||||
* execution, then the value set here will override the result code the
|
||||
* action had returned. Creating an Interceptor that implements
|
||||
* {@link PreResultListener} will give you this opportunity.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is called after the Result has been executed, it will
|
||||
* have the effect of raising an IllegalStateException.
|
||||
* </p>
|
||||
*
|
||||
* @param resultCode the result code.
|
||||
* @throws IllegalStateException if called after the Result has been executed.
|
||||
* @see #isExecuted()
|
||||
*/
|
||||
void setResultCode(String resultCode);
|
||||
|
||||
/**
|
||||
* Gets the ValueStack associated with this ActionInvocation.
|
||||
*
|
||||
* @return the ValueStack
|
||||
*/
|
||||
ValueStack getStack();
|
||||
|
||||
/**
|
||||
* Register a {@link PreResultListener} to be notified after the Action is executed and
|
||||
* before the Result is executed.
|
||||
*
|
||||
* <p>
|
||||
* The ActionInvocation implementation must guarantee that listeners will be called in
|
||||
* the order in which they are registered.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Listener registration and execution does not need to be thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @param listener the listener to add.
|
||||
*/
|
||||
void addPreResultListener(PreResultListener listener);
|
||||
|
||||
/**
|
||||
* Invokes the next step in processing this ActionInvocation.
|
||||
*
|
||||
* <p>
|
||||
* If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit
|
||||
* ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor
|
||||
* to execute. If there are no more Interceptors to be applied, the Action is executed.
|
||||
* If the {@link ActionProxy#getExecuteResult()} method returns <tt>true</tt>, the Result is also executed.
|
||||
* </p>
|
||||
*
|
||||
* @throws Exception can be thrown.
|
||||
* @return the return code.
|
||||
*/
|
||||
String invoke() throws Exception;
|
||||
|
||||
/**
|
||||
* Invokes only the Action (not Interceptors or Results).
|
||||
*
|
||||
* <p>
|
||||
* This is useful in rare situations where advanced usage with the interceptor/action/result workflow is
|
||||
* being manipulated for certain functionality.
|
||||
* </p>
|
||||
*
|
||||
* @return the return code.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
String invokeActionOnly() throws Exception;
|
||||
|
||||
/**
|
||||
* Sets the action event listener to respond to key action events.
|
||||
*
|
||||
* @param listener the listener.
|
||||
*/
|
||||
void setActionEventListener(ActionEventListener listener);
|
||||
|
||||
void init(ActionProxy proxy);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
|
||||
/**
|
||||
* ActionProxy is an extra layer between XWork and the action so that different proxies are possible.
|
||||
*
|
||||
* <p>
|
||||
* An example of this would be a remote proxy, where the layer between XWork and the action might be RMI or SOAP.
|
||||
* </p>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*/
|
||||
public interface ActionProxy {
|
||||
|
||||
/**
|
||||
* Gets the Action instance for this Proxy.
|
||||
*
|
||||
* @return the Action instance
|
||||
*/
|
||||
Object getAction();
|
||||
|
||||
/**
|
||||
* Gets the alias name this ActionProxy is mapped to.
|
||||
*
|
||||
* @return the alias name
|
||||
*/
|
||||
String getActionName();
|
||||
|
||||
/**
|
||||
* Gets the ActionConfig this ActionProxy is built from.
|
||||
*
|
||||
* @return the ActionConfig
|
||||
*/
|
||||
ActionConfig getConfig();
|
||||
|
||||
/**
|
||||
* Sets whether this ActionProxy should also execute the Result after executing the Action.
|
||||
*
|
||||
* @param executeResult <tt>true</tt> to also execute the Result.
|
||||
*/
|
||||
void setExecuteResult(boolean executeResult);
|
||||
|
||||
/**
|
||||
* Gets the status of whether the ActionProxy is set to execute the Result after the Action is executed.
|
||||
*
|
||||
* @return the status
|
||||
*/
|
||||
boolean getExecuteResult();
|
||||
|
||||
ActionInvocation getInvocation();
|
||||
|
||||
/**
|
||||
* Gets the namespace the ActionConfig for this ActionProxy is mapped to.
|
||||
*
|
||||
* @return the namespace
|
||||
*/
|
||||
String getNamespace();
|
||||
|
||||
/**
|
||||
* Execute this ActionProxy. This will set the ActionContext from the ActionInvocation into the ActionContext
|
||||
* ThreadLocal before invoking the ActionInvocation, then set the old ActionContext back into the ThreadLocal.
|
||||
*
|
||||
* @return the result code returned from executing the ActionInvocation
|
||||
* @throws Exception can be thrown.
|
||||
* @see ActionInvocation
|
||||
*/
|
||||
String execute() throws Exception;
|
||||
|
||||
/**
|
||||
* Gets the method name to execute, or <tt>null</tt> if no method has been specified (meaning <code>execute</code> will be invoked).
|
||||
*
|
||||
* @return the method to execute
|
||||
*/
|
||||
String getMethod();
|
||||
|
||||
/**
|
||||
* Gets status of the method value's initialization.
|
||||
*
|
||||
* @return true if the method returned by getMethod() is not a default initializer value.
|
||||
*/
|
||||
boolean isMethodSpecified();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
import com.opensymphony.xwork2.LocaleProvider;
|
||||
import com.opensymphony.xwork2.LocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.ValidationAwareSupport;
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Provides a default implementation for the most common actions.
|
||||
* See the documentation for all the interfaces this class implements for more detailed information.
|
||||
*/
|
||||
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ActionSupport.class);
|
||||
|
||||
private final ValidationAwareSupport validationAware = new ValidationAwareSupport();
|
||||
|
||||
private transient TextProvider textProvider;
|
||||
private transient LocaleProvider localeProvider;
|
||||
|
||||
protected Container container;
|
||||
|
||||
@Override
|
||||
public void setActionErrors(Collection<String> errorMessages) {
|
||||
validationAware.setActionErrors(errorMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionErrors() {
|
||||
return validationAware.getActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionMessages(Collection<String> messages) {
|
||||
validationAware.setActionMessages(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionMessages() {
|
||||
return validationAware.getActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFieldErrors(Map<String, List<String>> errorMap) {
|
||||
validationAware.setFieldErrors(errorMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getFieldErrors() {
|
||||
return validationAware.getFieldErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return getLocaleProvider().getLocale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocaleString(String localeStr) {
|
||||
return getLocaleProvider().isValidLocaleString(localeStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocale(Locale locale) {
|
||||
return getLocaleProvider().isValidLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale toLocale(String localeStr) {
|
||||
return getLocaleProvider().toLocale(localeStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey(String key) {
|
||||
return getTextProvider().hasKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName) {
|
||||
return getTextProvider().getText(aTextName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue) {
|
||||
return getTextProvider().getText(aTextName, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue, String obj) {
|
||||
return getTextProvider().getText(aTextName, defaultValue, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, List<?> args) {
|
||||
return getTextProvider().getText(aTextName, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String[] args) {
|
||||
return getTextProvider().getText(key, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue, List<?> args) {
|
||||
return getTextProvider().getText(aTextName, defaultValue, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, String[] args) {
|
||||
return getTextProvider().getText(key, defaultValue, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
|
||||
return getTextProvider().getText(key, defaultValue, args, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
|
||||
return getTextProvider().getText(key, defaultValue, args, stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedicated method to support I10N and conversion errors
|
||||
*
|
||||
* @param key message which contains formatting string
|
||||
* @param expr that should be formatted
|
||||
* @return formatted expr with format specified by key
|
||||
*/
|
||||
public String getFormatted(String key, String expr) {
|
||||
Map<String, ConversionData> conversionErrors = ActionContext.getContext().getConversionErrors();
|
||||
if (conversionErrors.containsKey(expr)) {
|
||||
String[] vals = (String[]) conversionErrors.get(expr).getValue();
|
||||
return vals[0];
|
||||
} else {
|
||||
var valueStack = ActionContext.getContext().getValueStack();
|
||||
final Object val = valueStack.findValue(expr);
|
||||
return getText(key, List.of(val));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundle getTexts() {
|
||||
return getTextProvider().getTexts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundle getTexts(String aBundleName) {
|
||||
return getTextProvider().getTexts(aBundleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionError(String anErrorMessage) {
|
||||
validationAware.addActionError(anErrorMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionMessage(String aMessage) {
|
||||
validationAware.addActionMessage(aMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFieldError(String fieldName, String errorMessage) {
|
||||
validationAware.addFieldError(fieldName, errorMessage);
|
||||
}
|
||||
|
||||
public String input() throws Exception {
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* A default implementation that does nothing an returns "success".
|
||||
*
|
||||
* <p>
|
||||
* Subclasses should override this method to provide their business logic.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* See also {@link Action#execute()}.
|
||||
* </p>
|
||||
*
|
||||
* @return returns {@link #SUCCESS}
|
||||
* @throws Exception can be thrown by subclasses.
|
||||
*/
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionErrors() {
|
||||
return validationAware.hasActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionMessages() {
|
||||
return validationAware.hasActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasErrors() {
|
||||
return validationAware.hasErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFieldErrors() {
|
||||
return validationAware.hasFieldErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears field errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearFieldErrors() {
|
||||
validationAware.clearFieldErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears action errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearActionErrors() {
|
||||
validationAware.clearActionErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears messages. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearMessages() {
|
||||
validationAware.clearMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearErrors() {
|
||||
validationAware.clearErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all errors and messages. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearErrorsAndMessages() {
|
||||
validationAware.clearErrorsAndMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* A default implementation that validates nothing.
|
||||
* Subclasses should override this method to provide validations.
|
||||
*/
|
||||
@Override
|
||||
public void validate() {
|
||||
// A default implementation that validates nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: pause-method -->
|
||||
* Stops the action invocation immediately (by throwing a PauseException) and causes the action invocation to return
|
||||
* the specified result, such as {@link #SUCCESS}, {@link #INPUT}, etc.
|
||||
*
|
||||
* <p>
|
||||
* The next time this action is invoked (and using the same continuation ID), the method will resume immediately
|
||||
* after where this method was called, with the entire call stack in the execute method restored.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note: this method can <b>only</b> be called within the {@link #execute()} method.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: pause-method -->
|
||||
*
|
||||
* @param result the result to return - the same type of return value in the {@link #execute()} method.
|
||||
*/
|
||||
public void pause(String result) {
|
||||
}
|
||||
|
||||
/**
|
||||
* If called first time it will create {@link TextProviderFactory},
|
||||
* inject dependency (if {@link Container} is accesible) into in,
|
||||
* then will create new {@link TextProvider} and store it in a field
|
||||
* for future references and at the returns reference to that field
|
||||
*
|
||||
* @return reference to field with TextProvider
|
||||
*/
|
||||
protected TextProvider getTextProvider() {
|
||||
if (textProvider == null) {
|
||||
final TextProviderFactory tpf = getContainer().getInstance(TextProviderFactory.class);
|
||||
textProvider = tpf.createInstance(getClass());
|
||||
}
|
||||
return textProvider;
|
||||
}
|
||||
|
||||
protected LocaleProvider getLocaleProvider() {
|
||||
if (localeProvider == null) {
|
||||
final LocaleProviderFactory localeProviderFactory = getContainer().getInstance(LocaleProviderFactory.class);
|
||||
localeProvider = localeProviderFactory.createLocaleProvider();
|
||||
}
|
||||
return localeProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This a temporary solution, maybe we should consider stop injecting container into beans
|
||||
*/
|
||||
protected Container getContainer() {
|
||||
if (container == null) {
|
||||
container = ActionContext.getContext().getContainer();
|
||||
if (container != null) {
|
||||
boolean devMode = Boolean.parseBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_DEVMODE));
|
||||
if (devMode) {
|
||||
LOG.warn("Container is null, action was created manually? Fallback to ActionContext");
|
||||
} else {
|
||||
LOG.debug("Container is null, action was created manually? Fallback to ActionContext");
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Container is null, action was created out of ActionContext scope?!?");
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setContainer(Container container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
/**
|
||||
* ModelDriven Actions provide a model object to be pushed onto the ValueStack
|
||||
* in addition to the Action itself, allowing a FormBean type approach like Struts.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*/
|
||||
public interface ModelDriven<T> {
|
||||
|
||||
/**
|
||||
* Gets the model to be pushed onto the ValueStack instead of the Action itself.
|
||||
*
|
||||
* @return the model
|
||||
*/
|
||||
@StrutsParameter(depth = Integer.MAX_VALUE)
|
||||
T getModel();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
/**
|
||||
* Preparable Actions will have their <code>prepare()</code> method called if the {@link com.opensymphony.xwork2.interceptor.PrepareInterceptor}
|
||||
* is applied to the ActionConfig.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see com.opensymphony.xwork2.interceptor.PrepareInterceptor
|
||||
*/
|
||||
public interface Preparable {
|
||||
|
||||
/**
|
||||
* This method is called to allow the action to prepare itself.
|
||||
*
|
||||
* @throws Exception thrown if a system level exception occurs.
|
||||
*/
|
||||
void prepare() throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* All results (except for <code>Action.NONE</code>) of an {@link Action} are mapped to a View implementation.
|
||||
*
|
||||
* <p>
|
||||
* Examples of Views might be:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>SwingPanelView - pops up a new Swing panel</li>
|
||||
* <li>ActionChainView - executes another action</li>
|
||||
* <li>SerlvetRedirectView - redirects the HTTP response to a URL</li>
|
||||
* <li>ServletDispatcherView - dispatches the HTTP response to a URL</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author plightbo
|
||||
*/
|
||||
public interface Result extends Serializable {
|
||||
|
||||
/**
|
||||
* Represents a generic interface for all action execution results.
|
||||
* Whether that be displaying a webpage, generating an email, sending a JMS message, etc.
|
||||
*
|
||||
* @param invocation the invocation context.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
void execute(ActionInvocation invocation) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
/**
|
||||
* Simple marker interface to indicate an object should <b>not</b> have its properties copied during chaining.
|
||||
*
|
||||
* @see com.opensymphony.xwork2.interceptor.ChainingInterceptor
|
||||
*/
|
||||
public interface Unchainable {
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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;
|
||||
|
||||
/**
|
||||
* Provides an interface in which a call for a validation check can be done.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see com.opensymphony.xwork2.ActionSupport
|
||||
* @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
|
||||
*/
|
||||
public interface Validateable {
|
||||
|
||||
/**
|
||||
* Performs validation.
|
||||
*/
|
||||
void validate();
|
||||
|
||||
}
|
||||
@@ -20,6 +20,7 @@ package org.apache.struts2.factory;
|
||||
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.factory.ResultFactory;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
@@ -54,16 +55,36 @@ public class StrutsResultFactory implements ResultFactory {
|
||||
Result result = null;
|
||||
|
||||
if (resultClassName != null) {
|
||||
result = (Result) objectFactory.buildBean(resultClassName, extraContext);
|
||||
Object o = objectFactory.buildBean(resultClassName, extraContext);
|
||||
Map<String, String> params = resultConfig.getParams();
|
||||
if (params != null) {
|
||||
setParameters(extraContext, result, params);
|
||||
setParameters(extraContext, o, params);
|
||||
}
|
||||
if (o instanceof Result) {
|
||||
result = (Result) o;
|
||||
} else if (o instanceof org.apache.struts2.Result) {
|
||||
result = Result.adapt((org.apache.struts2.Result) o);
|
||||
}
|
||||
if (result == null) {
|
||||
throw new ConfigurationException("Class [" + resultClassName + "] does not implement Result", resultConfig);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void setParameters(Map<String, Object> extraContext, Result result, Map<String, String> params) {
|
||||
setParametersHelper(extraContext, result, params);
|
||||
}
|
||||
|
||||
protected void setParameters(Map<String, Object> extraContext, Object result, Map<String, String> params) {
|
||||
if (result instanceof Result) {
|
||||
setParameters(extraContext, (Result) result, params);
|
||||
} else {
|
||||
setParametersHelper(extraContext, result, params);
|
||||
}
|
||||
}
|
||||
|
||||
private void setParametersHelper(Map<String, Object> extraContext, Object result, Map<String, String> params) {
|
||||
for (Map.Entry<String, String> paramEntry : params.entrySet()) {
|
||||
try {
|
||||
String name = paramEntry.getKey();
|
||||
@@ -78,6 +99,18 @@ public class StrutsResultFactory implements ResultFactory {
|
||||
}
|
||||
|
||||
protected void setParameter(Result result, String name, String value, Map<String, Object> extraContext) {
|
||||
setParameterHelper(result, name, value, extraContext);
|
||||
}
|
||||
|
||||
private void setParameter(Object result, String name, String value, Map<String, Object> extraContext) {
|
||||
if (result instanceof Result) {
|
||||
setParameter((Result) result, name, value, extraContext);
|
||||
} else {
|
||||
setParameterHelper(result, name, value, extraContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void setParameterHelper(Object result, String name, String value, Map<String, Object> extraContext) {
|
||||
if (result instanceof ParamNameAwareResult) {
|
||||
if (((ParamNameAwareResult) result).acceptableParameterName(name, value)) {
|
||||
reflectionProvider.setProperty(name, value, result, extraContext, true);
|
||||
@@ -86,5 +119,4 @@ public class StrutsResultFactory implements ResultFactory {
|
||||
reflectionProvider.setProperty(name, value, result, extraContext, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* Provides default implementations of optional lifecycle methods
|
||||
*/
|
||||
public abstract class AbstractInterceptor implements ConditionalInterceptor {
|
||||
|
||||
private boolean disabled;
|
||||
|
||||
/**
|
||||
* Does nothing
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to handle interception
|
||||
*/
|
||||
@Override
|
||||
public abstract String intercept(ActionInvocation invocation) throws Exception;
|
||||
|
||||
/**
|
||||
* Allows to skip executing a given interceptor, just define {@code <param name="disabled">true</param>}
|
||||
* or use other way to override interceptor's parameters, see
|
||||
* <a href="https://struts.apache.org/core-developers/interceptors#interceptor-parameter-overriding">docs</a>.
|
||||
* @param disable if set to true, execution of a given interceptor will be skipped.
|
||||
*/
|
||||
public void setDisabled(String disable) {
|
||||
this.disabled = Boolean.parseBoolean(disable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIntercept(ActionInvocation invocation) {
|
||||
return !this.disabled;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ package org.apache.struts2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.util.Evaluated;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.interceptor.parameter.ParametersInterceptor;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
*
|
||||
* The aim of this Interceptor is to alias a named parameter to a different named parameter. By acting as the glue
|
||||
* between actions sharing similar parameters (but with different names), it can help greatly with action chaining.
|
||||
*
|
||||
* <p>Action's alias expressions should be in the form of <code>#{ "name1" : "alias1", "name2" : "alias2" }</code>.
|
||||
* This means that assuming an action (or something else in the stack) has a value for the expression named <i>name1</i> and the
|
||||
* action this interceptor is applied to has a setter named <i>alias1</i>, <i>alias1</i> will be set with the value from
|
||||
* <i>name1</i>.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>aliasesKey (optional) - the name of the action parameter to look for the alias map (by default this is
|
||||
* <i>aliases</i>).</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <p><u>Extending the interceptor:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
*
|
||||
* This interceptor does not have any known extension points.
|
||||
*
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
* <p><u>Example code:</u></p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <!-- The value for the foo parameter will be applied as if it were named bar -->
|
||||
* <param name="aliases">#{ 'foo' : 'bar' }</param>
|
||||
*
|
||||
* <interceptor-ref name="alias"/>
|
||||
* <interceptor-ref name="basicStack"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
* @author Matthew Payne
|
||||
*/
|
||||
public class AliasInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(AliasInterceptor.class);
|
||||
|
||||
private static final String DEFAULT_ALIAS_KEY = "aliases";
|
||||
protected String aliasesKey = DEFAULT_ALIAS_KEY;
|
||||
|
||||
protected ValueStackFactory valueStackFactory;
|
||||
protected LocalizedTextProvider localizedTextProvider;
|
||||
protected boolean devMode = false;
|
||||
|
||||
private ExcludedPatternsChecker excludedPatterns;
|
||||
private AcceptedPatternsChecker acceptedPatterns;
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
public void setDevMode(String mode) {
|
||||
this.devMode = Boolean.parseBoolean(mode);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setValueStackFactory(ValueStackFactory valueStackFactory) {
|
||||
this.valueStackFactory = valueStackFactory;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setLocalizedTextProvider(LocalizedTextProvider localizedTextProvider) {
|
||||
this.localizedTextProvider = localizedTextProvider;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setExcludedPatterns(ExcludedPatternsChecker excludedPatterns) {
|
||||
this.excludedPatterns = excludedPatterns;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setAcceptedPatterns(AcceptedPatternsChecker acceptedPatterns) {
|
||||
this.acceptedPatterns = acceptedPatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Sets the name of the action parameter to look for the alias map.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Default is <code>aliases</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param aliasesKey the name of the action parameter
|
||||
*/
|
||||
public void setAliasesKey(String aliasesKey) {
|
||||
this.aliasesKey = aliasesKey;
|
||||
}
|
||||
|
||||
@Override public String intercept(ActionInvocation invocation) throws Exception {
|
||||
|
||||
ActionConfig config = invocation.getProxy().getConfig();
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
Object action = invocation.getAction();
|
||||
|
||||
// get the action's parameters
|
||||
final Map<String, String> parameters = config.getParams();
|
||||
|
||||
if (parameters.containsKey(aliasesKey)) {
|
||||
|
||||
String aliasExpression = parameters.get(aliasesKey);
|
||||
ValueStack stack = ac.getValueStack();
|
||||
Object obj = stack.findValue(aliasExpression);
|
||||
|
||||
if (obj instanceof Map) {
|
||||
//get secure stack
|
||||
ValueStack newStack = valueStackFactory.createValueStack(com.opensymphony.xwork2.util.ValueStack.adapt(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
|
||||
newStack.getActionContext().withLocale(stack.getActionContext().getLocale());
|
||||
}
|
||||
|
||||
// override
|
||||
Map aliases = (Map) obj;
|
||||
for (Object o : aliases.entrySet()) {
|
||||
Map.Entry entry = (Map.Entry) o;
|
||||
String name = entry.getKey().toString();
|
||||
if (isNotAcceptableExpression(name)) {
|
||||
continue;
|
||||
}
|
||||
String alias = (String) entry.getValue();
|
||||
if (isNotAcceptableExpression(alias)) {
|
||||
continue;
|
||||
}
|
||||
Evaluated value = new Evaluated(stack.findValue(name));
|
||||
if (!value.isDefined()) {
|
||||
// workaround
|
||||
HttpParameters contextParameters = ActionContext.getContext().getParameters();
|
||||
|
||||
if (null != contextParameters) {
|
||||
Parameter param = contextParameters.get(name);
|
||||
if (param.isDefined()) {
|
||||
value = new Evaluated(param.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value.isDefined()) {
|
||||
try {
|
||||
newStack.setValue(alias, value.get());
|
||||
} catch (RuntimeException e) {
|
||||
if (devMode) {
|
||||
String developerNotification = localizedTextProvider.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.getActionContext().withConversionErrors(newStack.getActionContext().getConversionErrors());
|
||||
}
|
||||
} else {
|
||||
LOG.debug("invalid alias expression: {}", aliasesKey);
|
||||
}
|
||||
}
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
protected boolean isAccepted(String paramName) {
|
||||
AcceptedPatternsChecker.IsAccepted result = acceptedPatterns.isAccepted(paramName);
|
||||
if (result.isAccepted()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG.warn("Parameter [{}] didn't match accepted pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getAcceptedPattern());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcluded(String paramName) {
|
||||
ExcludedPatternsChecker.IsExcluded result = excludedPatterns.isExcluded(paramName);
|
||||
if (!result.isExcluded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG.warn("Parameter [{}] matches excluded pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getExcludedPattern());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if expression contains vulnerable code
|
||||
*
|
||||
* @param expression of interceptor
|
||||
* @return true|false
|
||||
*/
|
||||
protected boolean isNotAcceptableExpression(String expression) {
|
||||
return isExcluded(expression) || !isAccepted(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a comma-delimited list of regular expressions to match
|
||||
* parameters that are allowed in the parameter map (aka whitelist).
|
||||
* <p>
|
||||
* Don't change the default unless you know what you are doing in terms
|
||||
* of security implications.
|
||||
* </p>
|
||||
*
|
||||
* @param commaDelim A comma-delimited list of regular expressions
|
||||
*/
|
||||
public void setAcceptParamNames(String commaDelim) {
|
||||
acceptedPatterns.setAcceptedPatterns(commaDelim);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
excludedPatterns.setExcludedPatterns(commaDelim);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionChainResult;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.ProxyUtil;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.Result;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.Unchainable;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* <p>
|
||||
* An interceptor that copies all the properties of every object in the value stack to the currently executing object,
|
||||
* except for any object that implements {@link Unchainable}. A collection of optional <i>includes</i> and
|
||||
* <i>excludes</i> may be provided to control how and which parameters are copied. Only includes or excludes may be
|
||||
* specified. Specifying both results in undefined behavior. See the javadocs for {@link ReflectionProvider#copy(Object, Object,
|
||||
* Map, Collection, Collection)} for more information.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> It is important to remember that this interceptor does nothing if there are no objects already on the stack.
|
||||
* <br>This means two things:
|
||||
* <br><b>One</b>, you can safely apply it to all your actions without any worry of adverse affects.
|
||||
* <br><b>Two</b>, it is up to you to ensure an object exists in the stack prior to invoking this action. The most typical way this is done
|
||||
* is through the use of the <b>chain</b> result type, which combines with this interceptor to make up the action
|
||||
* chaining feature.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> By default Errors, Field errors and Message aren't copied during chaining, to change the behaviour you can specify
|
||||
* the below three constants in struts.properties or struts.xml:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>struts.chaining.copyErrors - set to true to copy Action Errors</li>
|
||||
* <li>struts.chaining.copyFieldErrors - set to true to copy Field Errors</li>
|
||||
* <li>struts.chaining.copyMessages - set to true to copy Action Messages</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* <u>Example:</u>
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <constant name="struts.xwork.chaining.copyErrors" value="true"/>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> By default actionErrors and actionMessages are excluded when copping object's properties.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: description -->
|
||||
* <u>Interceptor parameters:</u>
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
* <ul>
|
||||
* <li>excludes (optional) - the list of parameter names to exclude from copying (all others will be included).</li>
|
||||
* <li>includes (optional) - the list of parameter names to include when copying (all others will be excluded).</li>
|
||||
* </ul>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
* <u>Extending the interceptor:</u>
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* <p>
|
||||
* There are no known extension points to this interceptor.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: extending -->
|
||||
* <u>Example code:</u>
|
||||
*
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <pre>
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="basicStack"/>
|
||||
* <result name="success" type="chain">otherAction</result>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <pre>
|
||||
* <action name="otherAction" class="com.examples.OtherAction">
|
||||
* <interceptor-ref name="chain"/>
|
||||
* <interceptor-ref name="basicStack"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
* </pre>
|
||||
* <!-- END SNIPPET: example -->
|
||||
*
|
||||
*
|
||||
* @author mrdon
|
||||
* @author tm_jee ( tm_jee(at)yahoo.co.uk )
|
||||
* @see ActionChainResult
|
||||
*/
|
||||
public class ChainingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ChainingInterceptor.class);
|
||||
|
||||
private static final String ACTION_ERRORS = "actionErrors";
|
||||
private static final String FIELD_ERRORS = "fieldErrors";
|
||||
private static final String ACTION_MESSAGES = "actionMessages";
|
||||
|
||||
private boolean copyMessages = false;
|
||||
private boolean copyErrors = false;
|
||||
private boolean copyFieldErrors = false;
|
||||
|
||||
protected Collection<String> excludes;
|
||||
|
||||
protected Collection<String> includes;
|
||||
protected ReflectionProvider reflectionProvider;
|
||||
|
||||
@Inject
|
||||
public void setReflectionProvider(ReflectionProvider prov) {
|
||||
this.reflectionProvider = prov;
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_CHAINING_COPY_ERRORS, required = false)
|
||||
public void setCopyErrors(String copyErrors) {
|
||||
this.copyErrors = "true".equalsIgnoreCase(copyErrors);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_CHAINING_COPY_FIELD_ERRORS, required = false)
|
||||
public void setCopyFieldErrors(String copyFieldErrors) {
|
||||
this.copyFieldErrors = "true".equalsIgnoreCase(copyFieldErrors);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_CHAINING_COPY_MESSAGES, required = false)
|
||||
public void setCopyMessages(String copyMessages) {
|
||||
this.copyMessages = "true".equalsIgnoreCase(copyMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
ValueStack stack = invocation.getStack();
|
||||
CompoundRoot root = stack.getRoot();
|
||||
if (shouldCopyStack(invocation, root)) {
|
||||
copyStack(invocation, root);
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
private void copyStack(ActionInvocation invocation, CompoundRoot root) {
|
||||
List list = prepareList(root);
|
||||
Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
|
||||
for (Object object : list) {
|
||||
if (shouldCopy(object)) {
|
||||
Object action = invocation.getAction();
|
||||
Class<?> editable = null;
|
||||
if(ProxyUtil.isProxy(action)) {
|
||||
editable = ProxyUtil.ultimateTargetClass(action);
|
||||
}
|
||||
reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, editable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<String> prepareExcludes() {
|
||||
Collection<String> localExcludes = excludes;
|
||||
if (!copyErrors || !copyMessages ||!copyFieldErrors) {
|
||||
if (localExcludes == null) {
|
||||
localExcludes = new HashSet<String>();
|
||||
if (!copyErrors) {
|
||||
localExcludes.add(ACTION_ERRORS);
|
||||
}
|
||||
if (!copyMessages) {
|
||||
localExcludes.add(ACTION_MESSAGES);
|
||||
}
|
||||
if (!copyFieldErrors) {
|
||||
localExcludes.add(FIELD_ERRORS);
|
||||
}
|
||||
}
|
||||
}
|
||||
return localExcludes;
|
||||
}
|
||||
|
||||
private boolean shouldCopy(Object o) {
|
||||
return o != null && !(o instanceof Unchainable);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List prepareList(CompoundRoot root) {
|
||||
List list = new ArrayList(root);
|
||||
list.remove(0);
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private boolean shouldCopyStack(ActionInvocation invocation, CompoundRoot root) throws Exception {
|
||||
Result result = invocation.getResult();
|
||||
return root.size() > 1 && (result == null || ActionChainResult.class.isAssignableFrom(result.getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of parameter names to exclude
|
||||
*
|
||||
* @return the exclude list
|
||||
*/
|
||||
public Collection<String> getExcludes() {
|
||||
return excludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of parameter names to exclude from copying (all others will be included).
|
||||
*
|
||||
* @param excludes the excludes list as comma separated String
|
||||
*/
|
||||
public void setExcludes(String excludes) {
|
||||
this.excludes = TextParseUtil.commaDelimitedStringToSet(excludes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of parameter names to exclude from copying (all others will be included).
|
||||
*
|
||||
* @param excludes the excludes list
|
||||
*/
|
||||
public void setExcludesCollection(Collection<String> excludes) {
|
||||
this.excludes = excludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of parameter names to include
|
||||
*
|
||||
* @return the include list
|
||||
*/
|
||||
public Collection<String> getIncludes() {
|
||||
return includes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of parameter names to include when copying (all others will be excluded).
|
||||
*
|
||||
* @param includes the includes list as comma separated String
|
||||
*/
|
||||
public void setIncludes(String includes) {
|
||||
this.includes = TextParseUtil.commaDelimitedStringToSet(includes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the list of parameter names to include when copying (all others will be excluded).
|
||||
*
|
||||
* @param includes the includes list
|
||||
*/
|
||||
public void setIncludesCollection(Collection<String> includes) {
|
||||
this.includes = includes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* A marking interface, when implemented allows to conditionally execute a given interceptor
|
||||
* within the current action invocation.
|
||||
*
|
||||
* @since Struts 6.1.1
|
||||
*/
|
||||
public interface ConditionalInterceptor extends Interceptor {
|
||||
|
||||
/**
|
||||
* Determines if a given interceptor should be executed in the current processing of action invocation.
|
||||
*
|
||||
* @param invocation current {@link ActionInvocation} to determine if the interceptor should be executed
|
||||
* @return true if the given interceptor should be included in the current action invocation
|
||||
* @since 6.1.1
|
||||
*/
|
||||
boolean shouldIntercept(ActionInvocation invocation);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* ConversionErrorInterceptor adds conversion errors from the ActionContext to the Action's field errors.
|
||||
*
|
||||
* <p>
|
||||
* This interceptor adds any error found in the {@link ActionContext}'s conversionErrors map as a field error (provided
|
||||
* that the action implements {@link ValidationAware}). In addition, any field that contains a validation error has its
|
||||
* original value saved such that any subsequent requests for that value return the original value rather than the value
|
||||
* in the action. This is important because if the value "abc" is submitted and can't be converted to an int, we want to
|
||||
* display the original string ("abc") again rather than the int value (likely 0, which would make very little sense to
|
||||
* the user).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> Since 2.5.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><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
* <li>None</li>
|
||||
* </ul>
|
||||
*
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <p> <u>Extending the interceptor:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
*
|
||||
* Because this interceptor is not web-specific, it abstracts the logic for whether an error should be added. This
|
||||
* allows for web-specific interceptors to use more complex logic in the {@link #shouldAddError} method for when a value
|
||||
* has a conversion error but is null or empty or otherwise indicates that the value was never actually entered by the
|
||||
* user.
|
||||
*
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
* <p> <u>Example code:</u></p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="conversionError"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*/
|
||||
public class ConversionErrorInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
public static final String ORIGINAL_PROPERTY_OVERRIDE = "original.property.override";
|
||||
|
||||
protected Object getOverrideExpr(ActionInvocation invocation, Object value) {
|
||||
return escape(value);
|
||||
}
|
||||
|
||||
protected String escape(Object value) {
|
||||
return "\"" + StringEscapeUtils.escapeJava(String.valueOf(value)) + "\"";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String doIntercept(ActionInvocation invocation) throws Exception {
|
||||
|
||||
ActionContext invocationContext = invocation.getInvocationContext();
|
||||
Map<String, ConversionData> conversionErrors = invocationContext.getConversionErrors();
|
||||
ValueStack stack = invocationContext.getValueStack();
|
||||
|
||||
HashMap<Object, Object> fakie = null;
|
||||
|
||||
for (Map.Entry<String, ConversionData> entry : conversionErrors.entrySet()) {
|
||||
String propertyName = entry.getKey();
|
||||
ConversionData conversionData = entry.getValue();
|
||||
|
||||
if (shouldAddError(propertyName, conversionData.getValue())) {
|
||||
String message = XWorkConverter.getConversionErrorMessage(propertyName, conversionData.getToClass(), com.opensymphony.xwork2.util.ValueStack.adapt(stack));
|
||||
|
||||
Object action = invocation.getAction();
|
||||
if (action instanceof ValidationAware) {
|
||||
ValidationAware va = (ValidationAware) action;
|
||||
va.addFieldError(propertyName, message);
|
||||
}
|
||||
|
||||
if (fakie == null) {
|
||||
fakie = new HashMap<>();
|
||||
}
|
||||
|
||||
fakie.put(propertyName, getOverrideExpr(invocation, conversionData.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
if (fakie != null) {
|
||||
// if there were some errors, put the original (fake) values in place right before the result
|
||||
stack.getContext().put(ORIGINAL_PROPERTY_OVERRIDE, fakie);
|
||||
invocation.addPreResultListener(new PreResultListener() {
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
Map<Object, Object> fakie = (Map<Object, Object>) invocation.getInvocationContext().get(ORIGINAL_PROPERTY_OVERRIDE);
|
||||
|
||||
if (fakie != null) {
|
||||
invocation.getStack().setExprOverrides(fakie);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
protected boolean shouldAddError(String propertyName, Object value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.interceptor.annotations.InputConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* <p>
|
||||
* An interceptor that makes sure there are not validation, conversion or action errors before allowing the interceptor chain to continue.
|
||||
* If a single FieldError or ActionError (including the ones replicated by the Message Store Interceptor in a redirection) is found, the INPUT result will be triggered.
|
||||
* <b>This interceptor does not perform any validation</b>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This interceptor does nothing if the name of the method being invoked is specified in the <b>excludeMethods</b>
|
||||
* parameter. <b>excludeMethods</b> accepts a comma-delimited list of method names. For example, requests to
|
||||
* <b>foo!input.action</b> and <b>foo!back.action</b> will be skipped by this interceptor if you set the
|
||||
* <b>excludeMethods</b> parameter to "input, back".
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> As this method extends off MethodFilterInterceptor, it is capable of
|
||||
* deciding if it is applicable only to selective methods in the action class. This is done by adding param tags
|
||||
* for the interceptor element, naming either a list of excluded method names and/or a list of included method
|
||||
* names, whereby includeMethods overrides excludedMethods. A single * sign is interpreted as wildcard matching
|
||||
* all methods for both parameters.
|
||||
* See {@link MethodFilterInterceptor} for more info.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This interceptor also supports the following interfaces which can implemented by actions:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>ValidationAware - implemented by ActionSupport class</li>
|
||||
* <li>ValidationWorkflowAware - allows changing result name programmatically</li>
|
||||
* <li>ValidationErrorAware - notifies action about errors and also allow change result name</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* You can also use InputConfig annotation to change result name returned when validation errors occurred.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
* <ul>
|
||||
* <li>inputResultName - Default to "input". Determine the result name to be returned when
|
||||
* an action / field error is found.</li>
|
||||
* </ul>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <p><u>Extending the interceptor:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
*
|
||||
* <p>There are no known extension points for this interceptor.</p>
|
||||
*
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
* <p><u>Example code:</u></p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
*
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="validation"/>
|
||||
* <interceptor-ref name="workflow"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
*
|
||||
* <-- In this case myMethod as well as mySecondMethod of the action class
|
||||
* will not pass through the workflow process -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="validation"/>
|
||||
* <interceptor-ref name="workflow">
|
||||
* <param name="excludeMethods">myMethod,mySecondMethod</param>
|
||||
* </interceptor-ref name="workflow">
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
*
|
||||
* <-- In this case, the result named "error" will be used when
|
||||
* an action / field error is found -->
|
||||
* <-- The Interceptor will only be applied for myWorkflowMethod method of action
|
||||
* classes, since this is the only included method while any others are excluded -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="validation"/>
|
||||
* <interceptor-ref name="workflow">
|
||||
* <param name="inputResultName">error</param>
|
||||
* <param name="excludeMethods">*</param>
|
||||
* <param name="includeMethods">myWorkflowMethod</param>
|
||||
* </interceptor-ref>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
*
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @author Rainer Hermanns
|
||||
* @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
|
||||
* @author Philip Luppens
|
||||
* @author tm_jee
|
||||
*/
|
||||
public class DefaultWorkflowInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
private static final long serialVersionUID = 7563014655616490865L;
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultWorkflowInterceptor.class);
|
||||
|
||||
private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
|
||||
|
||||
private String inputResultName = Action.INPUT;
|
||||
|
||||
/**
|
||||
* Set the <code>inputResultName</code> (result name to be returned when
|
||||
* a action / field error is found registered). Default to {@link Action#INPUT}
|
||||
*
|
||||
* @param inputResultName what result name to use when there was validation error(s).
|
||||
*/
|
||||
public void setInputResultName(String inputResultName) {
|
||||
this.inputResultName = inputResultName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept {@link ActionInvocation} and returns a <code>inputResultName</code>
|
||||
* when action / field errors is found registered.
|
||||
*
|
||||
* @param invocation the action invocation
|
||||
* @return String result name
|
||||
*/
|
||||
@Override
|
||||
protected String doIntercept(ActionInvocation invocation) throws Exception {
|
||||
Object action = invocation.getAction();
|
||||
|
||||
if (action instanceof ValidationAware) {
|
||||
ValidationAware validationAwareAction = (ValidationAware) action;
|
||||
|
||||
if (validationAwareAction.hasErrors()) {
|
||||
LOG.debug("Errors on action [{}], returning result name [{}]", validationAwareAction, inputResultName);
|
||||
|
||||
String resultName = inputResultName;
|
||||
resultName = processValidationWorkflowAware(action, resultName);
|
||||
resultName = processInputConfig(action, invocation.getProxy().getMethod(), resultName);
|
||||
resultName = processValidationErrorAware(action, resultName);
|
||||
|
||||
return resultName;
|
||||
}
|
||||
}
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process {@link com.opensymphony.xwork2.interceptor.ValidationWorkflowAware} interface
|
||||
*
|
||||
* @param action action object
|
||||
* @param currentResultName current result name
|
||||
*
|
||||
* @return result name
|
||||
*/
|
||||
private String processValidationWorkflowAware(final Object action, final String currentResultName) {
|
||||
String resultName = currentResultName;
|
||||
if (action instanceof ValidationWorkflowAware) {
|
||||
resultName = ((ValidationWorkflowAware) action).getInputResultName();
|
||||
LOG.debug("Changing result name from [{}] to [{}] because of processing [{}] interface applied to [{}]",
|
||||
currentResultName, resultName, ValidationWorkflowAware.class.getSimpleName(), action);
|
||||
}
|
||||
return resultName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process {@link InputConfig} annotation applied to method
|
||||
* @param action action object
|
||||
* @param method method
|
||||
* @param currentResultName current result name
|
||||
*
|
||||
* @return result name
|
||||
*
|
||||
* @throws Exception in case of any errors
|
||||
*/
|
||||
protected String processInputConfig(final Object action, final String method, final String currentResultName) throws Exception {
|
||||
String resultName = currentResultName;
|
||||
InputConfig annotation = MethodUtils.getAnnotation(action.getClass().getMethod(method, EMPTY_CLASS_ARRAY),
|
||||
InputConfig.class ,true,true);
|
||||
if (annotation != null) {
|
||||
if (StringUtils.isNotEmpty(annotation.methodName())) {
|
||||
resultName = (String) MethodUtils.invokeMethod(action, true, annotation.methodName());
|
||||
} else {
|
||||
resultName = annotation.resultName();
|
||||
}
|
||||
LOG.debug("Changing result name from [{}] to [{}] because of processing annotation [{}] on action [{}]",
|
||||
currentResultName, resultName, InputConfig.class.getSimpleName(), action);
|
||||
}
|
||||
return resultName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify action if it implements {@link com.opensymphony.xwork2.interceptor.ValidationErrorAware} interface
|
||||
*
|
||||
* @param action action object
|
||||
* @param currentResultName current result name
|
||||
*
|
||||
* @return result name
|
||||
* @see com.opensymphony.xwork2.interceptor.ValidationErrorAware
|
||||
*/
|
||||
protected String processValidationErrorAware(final Object action, final String currentResultName) {
|
||||
String resultName = currentResultName;
|
||||
if (action instanceof ValidationErrorAware) {
|
||||
resultName = ((ValidationErrorAware) action).actionErrorOccurred(currentResultName);
|
||||
LOG.debug("Changing result name from [{}] to [{}] because of processing interface [{}] on action [{}]",
|
||||
currentResultName, resultName, ValidationErrorAware.class.getSimpleName(), action);
|
||||
}
|
||||
return resultName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig;
|
||||
import com.opensymphony.xwork2.interceptor.ExceptionHolder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* <p>
|
||||
* This interceptor forms the core functionality of the exception handling feature. Exception handling allows you to map
|
||||
* an exception to a result code, just as if the action returned a result code instead of throwing an unexpected
|
||||
* exception. When an exception is encountered, it is wrapped with an {@link ExceptionHolder} and pushed on the stack,
|
||||
* providing easy access to the exception from within your result.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> While you can configure exception mapping in your configuration file at any point, the configuration
|
||||
* will not have any effect if this interceptor is not in the interceptor stack for your actions. It is recommended that
|
||||
* you make this interceptor the first interceptor on the stack, ensuring that it has full access to catch any
|
||||
* exception, even those caused by other interceptors.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>logEnabled (optional) - Should exceptions also be logged? (boolean true|false)</li>
|
||||
*
|
||||
* <li>logLevel (optional) - what log level should we use (<code>trace, debug, info, warn, error, fatal</code>)? - defaut is <code>debug</code></li>
|
||||
*
|
||||
* <li>logCategory (optional) - If provided we would use this category (eg. <code>com.mycompany.app</code>).
|
||||
* Default is to use <code>com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor</code>.</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* The parameters above enables us to log all thrown exceptions with stacktace in our own logfile,
|
||||
* and present a friendly webpage (with no stacktrace) to the end user.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <p><u>Extending the interceptor:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* <p>
|
||||
* If you want to add custom handling for publishing the Exception, you may override
|
||||
* {@link #publishException(ActionInvocation, ExceptionHolder)}. The default implementation
|
||||
* pushes the given ExceptionHolder on value stack. A custom implementation could add additional logging etc.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
* <p><u>Example code:</u></p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <xwork>
|
||||
* <package name="default" extends="xwork-default">
|
||||
* <global-results>
|
||||
* <result name="error" type="freemarker">error.ftl</result>
|
||||
* </global-results>
|
||||
*
|
||||
* <global-exception-mappings>
|
||||
* <exception-mapping exception="java.lang.Exception" result="error"/>
|
||||
* </global-exception-mappings>
|
||||
*
|
||||
* <action name="test">
|
||||
* <interceptor-ref name="exception"/>
|
||||
* <interceptor-ref name="basicStack"/>
|
||||
* <exception-mapping exception="com.acme.CustomException" result="custom_error"/>
|
||||
* <result name="custom_error">custom_error.ftl</result>
|
||||
* <result name="success" type="freemarker">test.ftl</result>
|
||||
* </action>
|
||||
* </package>
|
||||
* </xwork>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* This second example will also log the exceptions using our own category
|
||||
* <code>com.mycompany.app.unhandled</code> at WARN level.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example2 -->
|
||||
* <xwork>
|
||||
* <package name="something" extends="xwork-default">
|
||||
* <interceptors>
|
||||
* <interceptor-stack name="exceptionmappingStack">
|
||||
* <interceptor-ref name="exception">
|
||||
* <param name="logEnabled">true</param>
|
||||
* <param name="logCategory">com.mycompany.app.unhandled</param>
|
||||
* <param name="logLevel">WARN</param>
|
||||
* </interceptor-ref>
|
||||
* <interceptor-ref name="i18n"/>
|
||||
* <interceptor-ref name="staticParams"/>
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="validation">
|
||||
* <param name="excludeMethods">input,back,cancel,browse</param>
|
||||
* </interceptor-ref>
|
||||
* </interceptor-stack>
|
||||
* </interceptors>
|
||||
*
|
||||
* <default-interceptor-ref name="exceptionmappingStack"/>
|
||||
*
|
||||
* <global-results>
|
||||
* <result name="unhandledException">/unhandled-exception.jsp</result>
|
||||
* </global-results>
|
||||
*
|
||||
* <global-exception-mappings>
|
||||
* <exception-mapping exception="java.lang.Exception" result="unhandledException"/>
|
||||
* </global-exception-mappings>
|
||||
*
|
||||
* <action name="exceptionDemo" class="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingAction">
|
||||
* <exception-mapping exception="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingException"
|
||||
* result="damm"/>
|
||||
* <result name="input">index.jsp</result>
|
||||
* <result name="success">success.jsp</result>
|
||||
* <result name="damm">damm.jsp</result>
|
||||
* </action>
|
||||
*
|
||||
* </package>
|
||||
* </xwork>
|
||||
* <!-- END SNIPPET: example2 -->
|
||||
* </pre>
|
||||
*
|
||||
* @author Matthew E. Porter (matthew dot porter at metissian dot com)
|
||||
* @author Claus Ibsen
|
||||
*/
|
||||
public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class);
|
||||
|
||||
protected Logger categoryLogger;
|
||||
protected boolean logEnabled = false;
|
||||
protected String logCategory;
|
||||
protected String logLevel;
|
||||
|
||||
|
||||
public boolean isLogEnabled() {
|
||||
return logEnabled;
|
||||
}
|
||||
|
||||
public void setLogEnabled(boolean logEnabled) {
|
||||
this.logEnabled = logEnabled;
|
||||
}
|
||||
|
||||
public String getLogCategory() {
|
||||
return logCategory;
|
||||
}
|
||||
|
||||
public void setLogCategory(String logCatgory) {
|
||||
this.logCategory = logCatgory;
|
||||
}
|
||||
|
||||
public String getLogLevel() {
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
public void setLogLevel(String logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
String result;
|
||||
|
||||
try {
|
||||
result = invocation.invoke();
|
||||
} catch (Exception e) {
|
||||
if (isLogEnabled()) {
|
||||
handleLogging(e);
|
||||
}
|
||||
List<ExceptionMappingConfig> exceptionMappings = invocation.getProxy().getConfig().getExceptionMappings();
|
||||
ExceptionMappingConfig mappingConfig = this.findMappingFromExceptions(exceptionMappings, e);
|
||||
if (mappingConfig != null && mappingConfig.getResult()!=null) {
|
||||
Map<String, String> mappingParams = mappingConfig.getParams();
|
||||
// create a mutable HashMap since some interceptors will remove parameters, and parameterMap is immutable
|
||||
HttpParameters parameters = HttpParameters.create(mappingParams).build();
|
||||
invocation.getInvocationContext().withParameters(parameters);
|
||||
result = mappingConfig.getResult();
|
||||
publishException(invocation, new ExceptionHolder(e));
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the logging of the exception.
|
||||
*
|
||||
* @param e the exception to log.
|
||||
*/
|
||||
protected void handleLogging(Exception e) {
|
||||
if (logCategory != null) {
|
||||
if (categoryLogger == null) {
|
||||
// init category logger
|
||||
categoryLogger = LogManager.getLogger(logCategory);
|
||||
}
|
||||
doLog(categoryLogger, e);
|
||||
} else {
|
||||
doLog(LOG, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual logging.
|
||||
*
|
||||
* @param logger the provided logger to use.
|
||||
* @param e the exception to log.
|
||||
*/
|
||||
protected void doLog(Logger logger, Exception e) {
|
||||
if (logLevel == null) {
|
||||
logger.debug(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
if ("trace".equalsIgnoreCase(logLevel)) {
|
||||
logger.trace(e.getMessage(), e);
|
||||
} else if ("debug".equalsIgnoreCase(logLevel)) {
|
||||
logger.debug(e.getMessage(), e);
|
||||
} else if ("info".equalsIgnoreCase(logLevel)) {
|
||||
logger.info(e.getMessage(), e);
|
||||
} else if ("warn".equalsIgnoreCase(logLevel)) {
|
||||
logger.warn(e.getMessage(), e);
|
||||
} else if ("error".equalsIgnoreCase(logLevel)) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} else if ("fatal".equalsIgnoreCase(logLevel)) {
|
||||
logger.fatal(e.getMessage(), e);
|
||||
} else {
|
||||
throw new IllegalArgumentException("LogLevel [" + logLevel + "] is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find appropriate {@link ExceptionMappingConfig} based on provided Throwable
|
||||
*
|
||||
* @param exceptionMappings list of defined exception mappings
|
||||
* @param t caught exception
|
||||
* @return appropriate mapping or null
|
||||
*/
|
||||
protected ExceptionMappingConfig findMappingFromExceptions(List<ExceptionMappingConfig> exceptionMappings, Throwable t) {
|
||||
ExceptionMappingConfig config = null;
|
||||
// Check for specific exception mappings.
|
||||
if (exceptionMappings != null) {
|
||||
int deepest = Integer.MAX_VALUE;
|
||||
for (Object exceptionMapping : exceptionMappings) {
|
||||
ExceptionMappingConfig exceptionMappingConfig = (ExceptionMappingConfig) exceptionMapping;
|
||||
int depth = getDepth(exceptionMappingConfig.getExceptionClassName(), t);
|
||||
if (depth >= 0 && depth < deepest) {
|
||||
deepest = depth;
|
||||
config = exceptionMappingConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the depth to the superclass matching. 0 means ex matches exactly. Returns -1 if there's no match.
|
||||
* Otherwise, returns depth. Lowest depth wins.
|
||||
*
|
||||
* @param exceptionMapping the mapping classname
|
||||
* @param t the cause
|
||||
* @return the depth, if not found -1 is returned.
|
||||
*/
|
||||
public int getDepth(String exceptionMapping, Throwable t) {
|
||||
return getDepth(exceptionMapping, t.getClass(), 0);
|
||||
}
|
||||
|
||||
private int getDepth(String exceptionMapping, Class exceptionClass, int depth) {
|
||||
if (exceptionClass.getName().contains(exceptionMapping)) {
|
||||
// Found it!
|
||||
return depth;
|
||||
}
|
||||
// If we've gone as far as we can go and haven't found it...
|
||||
if (exceptionClass.equals(Throwable.class)) {
|
||||
return -1;
|
||||
}
|
||||
return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation to handle ExceptionHolder publishing. Pushes given ExceptionHolder on the stack.
|
||||
* Subclasses may override this to customize publishing.
|
||||
*
|
||||
* @param invocation The invocation to publish Exception for.
|
||||
* @param exceptionHolder The exceptionHolder wrapping the Exception to publish.
|
||||
*/
|
||||
protected void publishException(ActionInvocation invocation, ExceptionHolder exceptionHolder) {
|
||||
invocation.getStack().push(exceptionHolder);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: introduction -->
|
||||
*
|
||||
* <p>
|
||||
* An interceptor is a stateless class that follows the interceptor pattern, as
|
||||
* found in {@link jakarta.servlet.Filter} and in AOP languages.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Interceptors are objects that dynamically intercept Action invocations.
|
||||
* They provide the developer with the opportunity to define code that can be executed
|
||||
* before and/or after the execution of an action. They also have the ability
|
||||
* to prevent an action from executing. Interceptors provide developers a way to
|
||||
* encapsulate common functionality in a re-usable form that can be applied to
|
||||
* one or more Actions.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Interceptors <b>must</b> be stateless and not assume that a new instance will be created for each request or Action.
|
||||
* Interceptors may choose to either short-circuit the {@link ActionInvocation} execution and return a return code
|
||||
* (such as {@link org.apache.struts2.Action#SUCCESS}), or it may choose to do some processing before
|
||||
* and/or after delegating the rest of the procesing using {@link ActionInvocation#invoke()}.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: introduction -->
|
||||
*
|
||||
* <!-- START SNIPPET: parameterOverriding -->
|
||||
* <p>
|
||||
* Interceptor's parameter could be overridden through the following ways :-
|
||||
* </p>
|
||||
|
||||
* <b>Method 1:</b>
|
||||
* <pre>
|
||||
* <action name="myAction" class="myActionClass">
|
||||
* <interceptor-ref name="exception"/>
|
||||
* <interceptor-ref name="alias"/>
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="servletConfig"/>
|
||||
* <interceptor-ref name="prepare"/>
|
||||
* <interceptor-ref name="i18n"/>
|
||||
* <interceptor-ref name="chain"/>
|
||||
* <interceptor-ref name="modelDriven"/>
|
||||
* <interceptor-ref name="fileUpload"/>
|
||||
* <interceptor-ref name="staticParams"/>
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="conversionError"/>
|
||||
* <interceptor-ref name="validation">
|
||||
* <param name="excludeMethods">myValidationExcudeMethod</param>
|
||||
* </interceptor-ref>
|
||||
* <interceptor-ref name="workflow">
|
||||
* <param name="excludeMethods">myWorkflowExcludeMethod</param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <b>Method 2:</b>
|
||||
* <pre>
|
||||
* <action name="myAction" class="myActionClass">
|
||||
* <interceptor-ref name="defaultStack">
|
||||
* <param name="validation.excludeMethods">myValidationExcludeMethod</param>
|
||||
* <param name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* In the first method, the whole default stack is copied and the parameter then
|
||||
* changed accordingly.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* In the second method, the 'interceptor-ref' refer to an existing
|
||||
* interceptor-stack, namely defaultStack in this example, and override the validator
|
||||
* and workflow interceptor excludeMethods typically in this case. Note that in the
|
||||
* 'param' tag, the name attribute contains a dot (.) the word before the dot(.)
|
||||
* specifies the interceptor name whose parameter is to be overridden and the word after
|
||||
* the dot (.) specifies the parameter itself. Essetially it is as follows :-
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <interceptor-name>.<parameter-name>
|
||||
* </pre>
|
||||
* <p>
|
||||
* <b>Note</b> also that in this case the 'interceptor-ref' name attribute
|
||||
* is used to indicate an interceptor stack which makes sense as if it is referring
|
||||
* to the interceptor itself it would be just using Method 1 describe above.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: parameterOverriding -->
|
||||
*
|
||||
* <p>
|
||||
* <b>Nested Interceptor param overriding</b>
|
||||
* </p>
|
||||
*
|
||||
* <!-- START SNIPPET: nestedParameterOverriding -->
|
||||
* <p>
|
||||
* Interceptor stack parameter overriding could be nested into as many level as possible, though it would
|
||||
* be advisable not to nest it too deep as to avoid confusion, For example,
|
||||
* </p>
|
||||
* <pre>
|
||||
* <interceptor name="interceptor1" class="foo.bar.Interceptor1" />
|
||||
* <interceptor name="interceptor2" class="foo.bar.Interceptor2" />
|
||||
* <interceptor name="interceptor3" class="foo.bar.Interceptor3" />
|
||||
* <interceptor name="interceptor4" class="foo.bar.Interceptor4" />
|
||||
* <interceptor-stack name="stack1">
|
||||
* <interceptor-ref name="interceptor1" />
|
||||
* </interceptor-stack>
|
||||
* <interceptor-stack name="stack2">
|
||||
* <interceptor-ref name="intercetor2" />
|
||||
* <interceptor-ref name="stack1" />
|
||||
* </interceptor-stack>
|
||||
* <interceptor-stack name="stack3">
|
||||
* <interceptor-ref name="interceptor3" />
|
||||
* <interceptor-ref name="stack2" />
|
||||
* </interceptor-stack>
|
||||
* <interceptor-stack name="stack4">
|
||||
* <interceptor-ref name="interceptor4" />
|
||||
* <interceptor-ref name="stack3" />
|
||||
* </interceptor-stack>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Assuming the interceptor has the following properties
|
||||
* </p>
|
||||
*
|
||||
* <table border="1" summary="">
|
||||
* <tr>
|
||||
* <td>Interceptor</td>
|
||||
* <td>property</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor1</td>
|
||||
* <td>param1</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor2</td>
|
||||
* <td>param2</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor3</td>
|
||||
* <td>param3</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor4</td>
|
||||
* <td>param4</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>
|
||||
* We could override them as follows :
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <action ... >
|
||||
* <!-- to override parameters of interceptor located directly in the stack -->
|
||||
* <interceptor-ref name="stack4">
|
||||
* <param name="interceptor4.param4"> ... </param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
*
|
||||
* <action ... >
|
||||
* <!-- to override parameters of interceptor located under nested stack -->
|
||||
* <interceptor-ref name="stack4">
|
||||
* <param name="stack3.interceptor3.param3"> ... </param>
|
||||
* <param name="stack3.stack2.interceptor2.param2"> ... </param>
|
||||
* <param name="stack3.stack2.stack1.interceptor1.param1"> ... </param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <!-- END SNIPPET: nestedParameterOverriding -->
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @author tmjee
|
||||
*/
|
||||
public interface Interceptor extends Serializable {
|
||||
|
||||
/**
|
||||
* Called to let an interceptor clean up any resources it has allocated.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Called after an interceptor is created, but before any requests are processed using
|
||||
* {@link #intercept(ActionInvocation) intercept} , giving
|
||||
* the Interceptor a chance to initialize any needed resources.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the
|
||||
* request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code.
|
||||
*
|
||||
* @param invocation the action invocation
|
||||
* @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself.
|
||||
* @throws Exception any system-level error, as defined in {@link org.apache.struts2.Action#execute()}.
|
||||
*/
|
||||
String intercept(ActionInvocation invocation) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* <p>
|
||||
* 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 = LogManager.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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,6 @@ package org.apache.struts2.interceptor;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.interceptor.PreResultListener;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: javadoc -->
|
||||
*
|
||||
* <p>
|
||||
* 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 TokenInterceptor
|
||||
* @see TokenSessionStoreInterceptor
|
||||
* @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
|
||||
* @see com.opensymphony.xwork2.validator.ValidationInterceptor
|
||||
*/
|
||||
public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(MethodFilterInterceptor.class);
|
||||
|
||||
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 (!applyMethod) {
|
||||
LOG.debug("Skipping Interceptor... Method [{}] found in exclude list.", method);
|
||||
}
|
||||
return applyMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must override to implement the interceptor logic.
|
||||
*
|
||||
* @param invocation the action invocation
|
||||
* @return the result of invocation
|
||||
* @throws Exception in case of any errors
|
||||
*/
|
||||
protected abstract String doIntercept(ActionInvocation invocation) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.WildcardHelper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
|
||||
/**
|
||||
* Utility class contains common methods used by
|
||||
* {@link 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;
|
||||
for (String includeMethod : includeMethods) {
|
||||
if (!"*".equals(includeMethod) && includeMethod.contains("*")) {
|
||||
needsPatternMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (String excludeMethod : excludeMethods) {
|
||||
if (!"*".equals(excludeMethod) && excludeMethod.contains("*")) {
|
||||
needsPatternMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this section will try to honor the original logic, while
|
||||
// still allowing for wildcards later
|
||||
if (!needsPatternMatch && (includeMethods.contains("*") || includeMethods.isEmpty()) ) {
|
||||
if (excludeMethods.contains(method) && !includeMethods.contains(method)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// test the methods using pattern matching
|
||||
WildcardHelper wildcard = new WildcardHelper();
|
||||
String methodCopy = requireNonNullElse(method, "");
|
||||
for (String pattern : includeMethods) {
|
||||
if (pattern.contains("*")) {
|
||||
int[] compiledPattern = wildcard.compilePattern(pattern);
|
||||
HashMap<String, String> matchedPatterns = new HashMap<>();
|
||||
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<>();
|
||||
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.isEmpty() || 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
import org.apache.struts2.interceptor.parameter.ParametersInterceptor;
|
||||
import org.apache.struts2.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>
|
||||
* <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.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <!-- 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></p>
|
||||
*
|
||||
* <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;
|
||||
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
|
||||
if (newModel != null) {
|
||||
for (Object item : root) {
|
||||
if (item == newModel) {
|
||||
needsRefresh = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.action.NoParameters;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <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>
|
||||
* <p>
|
||||
* No intended extension point
|
||||
*
|
||||
* <pre>
|
||||
* <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>
|
||||
* </pre>
|
||||
*/
|
||||
public class ParameterRemoverInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ParameterRemoverInterceptor.class);
|
||||
|
||||
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();
|
||||
HttpParameters parameters = ac.getParameters();
|
||||
|
||||
if (parameters != null) {
|
||||
for (String removeName : paramNames) {
|
||||
try {
|
||||
Parameter parameter = parameters.get(removeName);
|
||||
if (parameter.isDefined() && this.paramValues.contains(parameter.getValue())) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* PreResultListeners may be registered with an {@link ActionInvocation} to get a callback after the
|
||||
* {@link org.apache.struts2.Action} has been executed but before the {@link org.apache.struts2.Result}
|
||||
* is executed.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*/
|
||||
public interface PreResultListener {
|
||||
|
||||
/**
|
||||
* This callback method will be called after the {@link org.apache.struts2.Action} execution and
|
||||
* before the {@link org.apache.struts2.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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.interceptor.PrefixMethodInvocationUtil;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.Preparable;
|
||||
|
||||
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>
|
||||
* <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>
|
||||
*
|
||||
* <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.ActionProxy}. For example, you can specify a
|
||||
* prepareInput() method that will be run before the invocation of the input method.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <!-- 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></p>
|
||||
*
|
||||
* <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 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>prepare</code> method should always be executed.
|
||||
* <p>
|
||||
* Default is <tt>true</tt>.
|
||||
* </p>
|
||||
*
|
||||
* @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
|
||||
* </p>
|
||||
* @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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import org.apache.struts2.ModelDriven;
|
||||
|
||||
/**
|
||||
* Adds the ability to set a model, probably retrieved from a given state.
|
||||
*/
|
||||
public interface ScopedModelDriven<T> extends ModelDriven<T> {
|
||||
|
||||
/**
|
||||
* @param model 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);
|
||||
|
||||
/**
|
||||
* @return the key under which the model is stored
|
||||
*/
|
||||
String getScopeKey();
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.StrutsException;
|
||||
|
||||
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.</p>
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <!-- 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></p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
*
|
||||
* <-- Basic usage -->
|
||||
* <interceptor name="scopedModelDriven" class="org.apache.struts2.interceptor.ScopedModelDrivenInterceptor" />
|
||||
*
|
||||
* <-- Using all available parameters -->
|
||||
* <interceptor name="gangsterForm" class="org.apache.struts2.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;
|
||||
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 StrutsException("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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.Parameterizable;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.interceptor.parameter.ParametersInterceptor;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
*
|
||||
* This interceptor populates the action with the static parameters defined in the action configuration. If the action
|
||||
* implements {@link 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 <param> elements within xwork.xml.</p>
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>None</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <p><u>Extending the interceptor:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
*
|
||||
* <p>There are no extension points to this interceptor.</p>
|
||||
*
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
* <p> <u>Example code:</u></p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="staticParams">
|
||||
* <param name="parse">true</param>
|
||||
* <param name="overwrite">false</param>
|
||||
* </interceptor-ref>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
* @author Patrick Lightbody
|
||||
*/
|
||||
public class StaticParametersInterceptor extends AbstractInterceptor {
|
||||
|
||||
private boolean parse;
|
||||
private boolean overwrite;
|
||||
private boolean merge = true;
|
||||
private boolean devMode = false;
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(StaticParametersInterceptor.class);
|
||||
|
||||
private ValueStackFactory valueStackFactory;
|
||||
private LocalizedTextProvider localizedTextProvider;
|
||||
|
||||
@Inject
|
||||
public void setValueStackFactory(ValueStackFactory valueStackFactory) {
|
||||
this.valueStackFactory = valueStackFactory;
|
||||
}
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
public void setDevMode(String mode) {
|
||||
devMode = BooleanUtils.toBoolean(mode);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setLocalizedTextProvider(LocalizedTextProvider localizedTextProvider) {
|
||||
this.localizedTextProvider = localizedTextProvider;
|
||||
}
|
||||
|
||||
public void setParse(String value) {
|
||||
this.parse = BooleanUtils.toBoolean(value);
|
||||
}
|
||||
|
||||
public void setMerge(String value) {
|
||||
this.merge = BooleanUtils.toBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites already existing parameters from other sources.
|
||||
* Static parameters are the successor over previously set parameters, if true.
|
||||
*
|
||||
* @param value enable overwrites of already existing parameters from other sources
|
||||
*/
|
||||
public void setOverwrite(String value) {
|
||||
this.overwrite = BooleanUtils.toBoolean(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
ActionConfig config = invocation.getProxy().getConfig();
|
||||
Object action = invocation.getAction();
|
||||
|
||||
final Map<String, String> parameters = config.getParams();
|
||||
|
||||
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(com.opensymphony.xwork2.util.ValueStack.adapt(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
|
||||
newStack.getActionContext().withLocale(stack.getActionContext().getLocale());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||
Object val = entry.getValue();
|
||||
if (parse && val instanceof String) {
|
||||
val = TextParseUtil.translateVariables(val.toString(), com.opensymphony.xwork2.util.ValueStack.adapt(stack));
|
||||
}
|
||||
try {
|
||||
newStack.setValue(entry.getKey(), val);
|
||||
} catch (RuntimeException e) {
|
||||
if (devMode) {
|
||||
|
||||
String developerNotification = localizedTextProvider.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.getActionContext().withConversionErrors(newStack.getActionContext().getConversionErrors());
|
||||
}
|
||||
|
||||
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 parameters 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) {
|
||||
HttpParameters previousParams = ac.getParameters();
|
||||
|
||||
HttpParameters.Builder combinedParams;
|
||||
if (overwrite) {
|
||||
combinedParams = HttpParameters.create().withParent( previousParams);
|
||||
combinedParams = combinedParams.withExtraParams(newParams);
|
||||
} else {
|
||||
combinedParams = HttpParameters.create(newParams);
|
||||
combinedParams = combinedParams.withExtraParams(previousParams);
|
||||
}
|
||||
ac.withParameters(combinedParams.build());
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ package org.apache.struts2.interceptor;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ValidationAware classes can accept Action (class level) or field level error messages. Action level messages are kept
|
||||
* in a Collection. Field level error messages are kept in a Map from String field name to a List of field error msgs.
|
||||
*/
|
||||
public interface ValidationAware {
|
||||
|
||||
/**
|
||||
* Set the Collection of Action-level String error messages.
|
||||
*
|
||||
* @param errorMessages Collection of String error messages
|
||||
*/
|
||||
void setActionErrors(Collection<String> errorMessages);
|
||||
|
||||
/**
|
||||
* Get the Collection of Action-level error messages for this action. Error messages should not
|
||||
* be added directly here, as implementations are free to return a new Collection or an
|
||||
* Unmodifiable Collection.
|
||||
*
|
||||
* @return Collection of String error messages
|
||||
*/
|
||||
Collection<String> getActionErrors();
|
||||
|
||||
/**
|
||||
* Set the Collection of Action-level String messages (not errors).
|
||||
*
|
||||
* @param messages Collection of String messages (not errors).
|
||||
*/
|
||||
void setActionMessages(Collection<String> messages);
|
||||
|
||||
/**
|
||||
* Get the Collection of Action-level messages for this action. Messages should not be added
|
||||
* directly here, as implementations are free to return a new Collection or an Unmodifiable
|
||||
* Collection.
|
||||
*
|
||||
* @return Collection of String messages
|
||||
*/
|
||||
Collection<String> getActionMessages();
|
||||
|
||||
/**
|
||||
* Set the field error map of fieldname (String) to Collection of String error messages.
|
||||
*
|
||||
* @param errorMap field error map
|
||||
*/
|
||||
void setFieldErrors(Map<String, List<String>> errorMap);
|
||||
|
||||
/**
|
||||
* Get the field specific errors associated with this action. Error messages should not be added
|
||||
* directly here, as implementations are free to return a new Collection or an Unmodifiable
|
||||
* Collection.
|
||||
*
|
||||
* @return Map with errors mapped from fieldname (String) to Collection of String error messages
|
||||
*/
|
||||
Map<String, List<String>> getFieldErrors();
|
||||
|
||||
/**
|
||||
* Add an Action-level error message to this Action.
|
||||
*
|
||||
* @param anErrorMessage the error message
|
||||
*/
|
||||
void addActionError(String anErrorMessage);
|
||||
|
||||
/**
|
||||
* Add an Action-level message to this Action.
|
||||
*
|
||||
* @param aMessage the message
|
||||
*/
|
||||
void addActionMessage(String aMessage);
|
||||
|
||||
/**
|
||||
* Add an error message for a given field.
|
||||
*
|
||||
* @param fieldName name of field
|
||||
* @param errorMessage the error message
|
||||
*/
|
||||
void addFieldError(String fieldName, String errorMessage);
|
||||
|
||||
/**
|
||||
* Check whether there are any Action-level error messages.
|
||||
*
|
||||
* @return true if any Action-level error messages have been registered
|
||||
*/
|
||||
boolean hasActionErrors();
|
||||
|
||||
/**
|
||||
* Checks whether there are any Action-level messages.
|
||||
*
|
||||
* @return true if any Action-level messages have been registered
|
||||
*/
|
||||
boolean hasActionMessages();
|
||||
|
||||
/**
|
||||
* Checks whether there are any action errors or field errors.
|
||||
*
|
||||
* @return <code>(hasActionErrors() || hasFieldErrors())</code>
|
||||
*/
|
||||
default boolean hasErrors() {
|
||||
return hasActionErrors() || hasFieldErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there are any field errors associated with this action.
|
||||
*
|
||||
* @return whether there are any field errors
|
||||
*/
|
||||
boolean hasFieldErrors();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
/**
|
||||
* ValidationErrorAware classes can be notified about validation errors
|
||||
* before {@link com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor} will return 'inputResultName' result
|
||||
* to allow change or not the result name
|
||||
*
|
||||
* This interface can be only applied to action which already implements {@link ValidationAware} interface!
|
||||
*
|
||||
* @since 2.3.15
|
||||
*/
|
||||
public interface ValidationErrorAware {
|
||||
|
||||
/**
|
||||
* Allows to notify action about occurred action/field errors
|
||||
*
|
||||
* @param currentResultName current result name, action can change it or return the same
|
||||
* @return new result name or passed currentResultName
|
||||
*/
|
||||
String actionErrorOccurred(final String currentResultName);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.interceptor;
|
||||
|
||||
/**
|
||||
* ValidationWorkflowAware classes can programmatically change result name when errors occurred
|
||||
*
|
||||
* This interface can be only applied to action which already implements {@link ValidationAware} interface!
|
||||
*/
|
||||
public interface ValidationWorkflowAware {
|
||||
|
||||
String getInputResultName();
|
||||
|
||||
}
|
||||
@@ -154,7 +154,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics {
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the location it was created with, mainly for testing
|
||||
*
|
||||
@@ -201,9 +201,10 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics {
|
||||
* @param invocation the execution state of the action.
|
||||
* @throws Exception if an error occurs while executing the result.
|
||||
*/
|
||||
@Override
|
||||
public void execute(ActionInvocation invocation) throws Exception {
|
||||
lastFinalLocation = parseLocation ? conditionalParse(location, invocation) : location;
|
||||
doExecute(lastFinalLocation, invocation);
|
||||
doExecute(lastFinalLocation, (org.apache.struts2.ActionInvocation) invocation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,7 +217,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics {
|
||||
protected String conditionalParse(String param, ActionInvocation invocation) {
|
||||
if (parse && param != null && invocation != null) {
|
||||
return TextParseUtil.translateVariables(
|
||||
param,
|
||||
param,
|
||||
invocation.getStack(),
|
||||
new EncodingParsedValueEvaluator());
|
||||
} else {
|
||||
@@ -228,7 +229,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics {
|
||||
* As {@link #conditionalParse(String, ActionInvocation)} but does not
|
||||
* convert found object into String. If found object is a collection it is
|
||||
* returned if found object is not a collection it is wrapped in one.
|
||||
*
|
||||
*
|
||||
* @param param parameter
|
||||
* @param invocation action invocation
|
||||
* @param excludeEmptyElements 'true' for excluding empty elements
|
||||
@@ -237,7 +238,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics {
|
||||
protected Collection<String> conditionalParseCollection(String param, ActionInvocation invocation, boolean excludeEmptyElements) {
|
||||
if (parse && param != null && invocation != null) {
|
||||
return TextParseUtil.translateVariablesCollection(
|
||||
param,
|
||||
param,
|
||||
invocation.getStack(),
|
||||
excludeEmptyElements,
|
||||
new EncodingParsedValueEvaluator());
|
||||
@@ -251,9 +252,10 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics {
|
||||
/**
|
||||
* {@link com.opensymphony.xwork2.util.TextParseUtil.ParsedValueEvaluator} to do URL encoding for found values. To be
|
||||
* used for single strings or collections.
|
||||
*
|
||||
*
|
||||
*/
|
||||
private final class EncodingParsedValueEvaluator implements TextParseUtil.ParsedValueEvaluator {
|
||||
@Override
|
||||
public Object evaluate(String parsedValue) {
|
||||
if (encode) {
|
||||
if (parsedValue != null) {
|
||||
@@ -269,6 +271,13 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.7.0, override {@link #doExecute(String, org.apache.struts2.ActionInvocation)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the result given a final location (jsp page, action, etc) and the action invocation
|
||||
* (the state in which the action was executed). Subclasses must implement this class to handle
|
||||
@@ -278,5 +287,7 @@ public abstract class StrutsResultSupport implements Result, StrutsStatics {
|
||||
* @param invocation the execution state of the action.
|
||||
* @throws Exception if an error occurs while executing the result.
|
||||
*/
|
||||
protected abstract void doExecute(String finalLocation, ActionInvocation invocation) throws Exception;
|
||||
protected void doExecute(String finalLocation, org.apache.struts2.ActionInvocation invocation) throws Exception {
|
||||
doExecute(finalLocation, ActionInvocation.adapt(invocation));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.util;
|
||||
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import org.apache.struts2.ActionContext;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ValueStack allows multiple beans to be pushed in and dynamic EL expressions to be evaluated against it. When
|
||||
* evaluating an expression, the stack will be searched down the stack, from the latest objects pushed in to the
|
||||
* earliest, looking for a bean with a getter or setter for the given property or a method of the given name (depending
|
||||
* on the expression being evaluated).
|
||||
*/
|
||||
public interface ValueStack {
|
||||
|
||||
String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
|
||||
|
||||
String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp";
|
||||
|
||||
/**
|
||||
* Gets the context for this value stack. The context holds all the information in the value stack and it's surroundings.
|
||||
*
|
||||
* @return the context.
|
||||
*/
|
||||
Map<String, Object> getContext();
|
||||
|
||||
ActionContext getActionContext();
|
||||
|
||||
/**
|
||||
* Sets the default type to convert to if no type is provided when getting a value.
|
||||
*
|
||||
* @param defaultType the new default type
|
||||
*/
|
||||
void setDefaultType(Class defaultType);
|
||||
|
||||
/**
|
||||
* Set a override map containing <code> key -> values </code> that takes precedent when doing find operations on the ValueStack.
|
||||
* <p>
|
||||
* See the unit test for ValueStackTest for examples.
|
||||
* </p>
|
||||
*
|
||||
* @param overrides overrides map.
|
||||
*/
|
||||
void setExprOverrides(Map<Object, Object> overrides);
|
||||
|
||||
/**
|
||||
* Gets the override map if anyone exists.
|
||||
*
|
||||
* @return the override map, <tt>null</tt> if not set.
|
||||
*/
|
||||
Map<Object, Object> getExprOverrides();
|
||||
|
||||
/**
|
||||
* Get the CompoundRoot which holds the objects pushed onto the stack
|
||||
*
|
||||
* @return the root
|
||||
*/
|
||||
CompoundRoot getRoot();
|
||||
|
||||
/**
|
||||
* Attempts to set a property on a bean in the stack with the given expression using the default search order.
|
||||
*
|
||||
* @param expr the expression defining the path to the property to be set.
|
||||
* @param value the value to be set into the named property
|
||||
*/
|
||||
void setValue(String expr, Object value);
|
||||
|
||||
/**
|
||||
* Attempts to set a property on a bean in the stack with the given expression using the default search order.
|
||||
* N.B.: unlike #setValue(String,Object) it doesn't allow eval expression.
|
||||
* @param expr the expression defining the path to the property to be set.
|
||||
* @param value the value to be set into the named property
|
||||
*/
|
||||
void setParameter(String expr, Object value);
|
||||
|
||||
/**
|
||||
* Attempts to set a property on a bean in the stack with the given expression using the default search order.
|
||||
*
|
||||
* @param expr the expression defining the path to the property to be set.
|
||||
* @param value the value to be set into the named property
|
||||
* @param throwExceptionOnFailure a flag to tell whether an exception should be thrown if there is no property with
|
||||
* the given name.
|
||||
*/
|
||||
void setValue(String expr, Object value, boolean throwExceptionOnFailure);
|
||||
|
||||
String findString(String expr);
|
||||
String findString(String expr, boolean throwExceptionOnFailure);
|
||||
|
||||
/**
|
||||
* Find a value by evaluating the given expression against the stack in the default search order.
|
||||
*
|
||||
* @param expr the expression giving the path of properties to navigate to find the property value to return
|
||||
* @return the result of evaluating the expression
|
||||
*/
|
||||
Object findValue(String expr);
|
||||
|
||||
Object findValue(String expr, boolean throwExceptionOnFailure);
|
||||
|
||||
/**
|
||||
* Find a value by evaluating the given expression against the stack in the default search order.
|
||||
*
|
||||
* @param expr the expression giving the path of properties to navigate to find the property value to return
|
||||
* @param asType the type to convert the return value to
|
||||
* @return the result of evaluating the expression
|
||||
*/
|
||||
Object findValue(String expr, Class asType);
|
||||
Object findValue(String expr, Class asType, boolean throwExceptionOnFailure);
|
||||
|
||||
/**
|
||||
* Get the object on the top of the stack <b>without</b> changing the stack.
|
||||
*
|
||||
* @return the object on the top.
|
||||
* @see CompoundRoot#peek()
|
||||
*/
|
||||
Object peek();
|
||||
|
||||
/**
|
||||
* Get the object on the top of the stack and <b>remove</b> it from the stack.
|
||||
*
|
||||
* @return the object on the top of the stack
|
||||
* @see CompoundRoot#pop()
|
||||
*/
|
||||
Object pop();
|
||||
|
||||
/**
|
||||
* Put this object onto the top of the stack
|
||||
*
|
||||
* @param o the object to be pushed onto the stack
|
||||
* @see CompoundRoot#push(Object)
|
||||
*/
|
||||
void push(Object o);
|
||||
|
||||
/**
|
||||
* Sets an object on the stack with the given key
|
||||
* so it is retrievable by {@link #findValue(String)}, {@link #findValue(String, Class)}
|
||||
*
|
||||
* @param key the key
|
||||
* @param o the object
|
||||
*/
|
||||
void set(String key, Object o);
|
||||
|
||||
/**
|
||||
* Get the number of objects in the stack
|
||||
*
|
||||
* @return the number of objects in the stack
|
||||
*/
|
||||
int size();
|
||||
|
||||
}
|
||||
@@ -61,7 +61,7 @@ public class ScopesHashModel extends SimpleHash implements TemplateModel {
|
||||
private final ServletContext servletContext;
|
||||
private ValueStack stack;
|
||||
private final Map<String, TemplateModel> unlistedModels = new HashMap<>();
|
||||
private volatile Object parametersCache;
|
||||
private volatile Object attributesCache;
|
||||
|
||||
public ScopesHashModel(ObjectWrapper objectWrapper, ServletContext context, HttpServletRequest request, ValueStack stack) {
|
||||
super(objectWrapper);
|
||||
@@ -155,12 +155,12 @@ public class ScopesHashModel extends SimpleHash implements TemplateModel {
|
||||
|
||||
private Object findValueOnStack(final String key) {
|
||||
if (TAG_ATTRIBUTES.equals(key)) {
|
||||
if (parametersCache != null) {
|
||||
return parametersCache;
|
||||
if (attributesCache != null) {
|
||||
return attributesCache;
|
||||
}
|
||||
Object parametersLocal = stack.findValue(key);
|
||||
parametersCache = parametersLocal;
|
||||
return parametersLocal;
|
||||
Object attributesLocal = stack.findValue(key);
|
||||
attributesCache = attributesLocal;
|
||||
return attributesLocal;
|
||||
}
|
||||
return stack.findValue(key);
|
||||
}
|
||||
|
||||
+27
-3
@@ -50,6 +50,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
|
||||
Class.forName("java.io.Serializable"),
|
||||
Class.forName("com.opensymphony.xwork2.mock.MockResult"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.ConditionalInterceptor"),
|
||||
Class.forName("org.apache.struts2.ActionSupport"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionSupport"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionChainResult"),
|
||||
Class.forName("com.opensymphony.xwork2.TextProvider"),
|
||||
@@ -60,8 +61,15 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
|
||||
Class.forName("com.opensymphony.xwork2.mock.MockInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Action"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"),
|
||||
Class.forName("org.apache.struts2.interceptor.AbstractInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Result"),
|
||||
Class.forName("com.opensymphony.xwork2.SimpleAction")
|
||||
Class.forName("com.opensymphony.xwork2.SimpleAction"),
|
||||
Class.forName("org.apache.struts2.interceptor.Interceptor"),
|
||||
Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"),
|
||||
Class.forName("org.apache.struts2.Result"),
|
||||
Class.forName("org.apache.struts2.Action"),
|
||||
Class.forName("org.apache.struts2.Validateable"),
|
||||
Class.forName("org.apache.struts2.interceptor.ValidationAware")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -76,6 +84,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
|
||||
Class.forName("java.io.Serializable"),
|
||||
Class.forName("com.opensymphony.xwork2.mock.MockResult"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.ConditionalInterceptor"),
|
||||
Class.forName("org.apache.struts2.ActionSupport"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionSupport"),
|
||||
Class.forName("com.opensymphony.xwork2.TextProvider"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.Interceptor"),
|
||||
@@ -84,8 +93,15 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
|
||||
Class.forName("com.opensymphony.xwork2.mock.MockInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Action"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"),
|
||||
Class.forName("org.apache.struts2.interceptor.AbstractInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Result"),
|
||||
Class.forName("com.opensymphony.xwork2.SimpleAction")
|
||||
Class.forName("com.opensymphony.xwork2.SimpleAction"),
|
||||
Class.forName("org.apache.struts2.interceptor.Interceptor"),
|
||||
Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"),
|
||||
Class.forName("org.apache.struts2.Result"),
|
||||
Class.forName("org.apache.struts2.Action"),
|
||||
Class.forName("org.apache.struts2.Validateable"),
|
||||
Class.forName("org.apache.struts2.interceptor.ValidationAware")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -99,6 +115,7 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
|
||||
Class.forName("com.opensymphony.xwork2.LocaleProvider"),
|
||||
Class.forName("java.io.Serializable"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.ConditionalInterceptor"),
|
||||
Class.forName("org.apache.struts2.ActionSupport"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionSupport"),
|
||||
Class.forName("com.opensymphony.xwork2.ActionChainResult"),
|
||||
Class.forName("com.opensymphony.xwork2.TextProvider"),
|
||||
@@ -108,7 +125,14 @@ public class ConfigurationProviderOgnlAllowlistTest extends XWorkJUnit4TestCase
|
||||
Class.forName("com.opensymphony.xwork2.Validateable"),
|
||||
Class.forName("com.opensymphony.xwork2.Action"),
|
||||
Class.forName("com.opensymphony.xwork2.interceptor.AbstractInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Result")
|
||||
Class.forName("org.apache.struts2.interceptor.AbstractInterceptor"),
|
||||
Class.forName("com.opensymphony.xwork2.Result"),
|
||||
Class.forName("org.apache.struts2.interceptor.Interceptor"),
|
||||
Class.forName("org.apache.struts2.interceptor.ConditionalInterceptor"),
|
||||
Class.forName("org.apache.struts2.Result"),
|
||||
Class.forName("org.apache.struts2.Action"),
|
||||
Class.forName("org.apache.struts2.Validateable"),
|
||||
Class.forName("org.apache.struts2.interceptor.ValidationAware")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+152
-6
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.ValidationAwareSupport;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import com.opensymphony.xwork2.mock.MockActionProxy;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletDiskFileUpload;
|
||||
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletFileUpload;
|
||||
@@ -268,12 +269,10 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
public void testNoContentMultipartRequest() throws Exception {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
|
||||
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
req.setMethod("post");
|
||||
req.addHeader("Content-type", "multipart/form-data");
|
||||
req.setContent(null); // there is no content
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.addHeader("Content-type", "multipart/form-data");
|
||||
request.setContent(null); // there is no content
|
||||
|
||||
MyFileUploadAction action = container.inject(MyFileUploadAction.class);
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
@@ -324,6 +323,145 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
assertNotNull("deleteme.txt", files.get(0).getOriginalName());
|
||||
}
|
||||
|
||||
public void testSuccessUploadOfATextFileMultipartRequestNoMaxParamsSet() throws Exception {
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.addHeader("Content-type", "multipart/form-data; boundary=---1234");
|
||||
|
||||
// inspired by the unit tests for jakarta commons fileupload
|
||||
String content = ("-----1234\r\n" +
|
||||
"Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" +
|
||||
"Content-Type: text/html\r\n" +
|
||||
"\r\n" +
|
||||
"Unit test of ActionFileUploadInterceptor" +
|
||||
"\r\n" +
|
||||
"-----1234--\r\n");
|
||||
request.setContent(content.getBytes(StandardCharsets.US_ASCII));
|
||||
|
||||
MyFileUploadAction action = new MyFileUploadAction();
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("success");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet());
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertFalse(action.hasErrors());
|
||||
|
||||
List<UploadedFile> files = action.getUploadFiles();
|
||||
|
||||
assertNotNull(files);
|
||||
assertEquals(1, files.size());
|
||||
assertEquals("text/html", files.get(0).getContentType());
|
||||
assertNotNull("deleteme.txt", files.get(0).getOriginalName());
|
||||
}
|
||||
|
||||
public void testSuccessUploadOfATextFileMultipartRequestWithNormalFieldsMaxParamsSet() throws Exception {
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.addHeader("Content-type", "multipart/form-data; boundary=---1234");
|
||||
|
||||
// inspired by the unit tests for jakarta commons fileupload
|
||||
String content = ("-----1234\r\n" +
|
||||
"Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" +
|
||||
"Content-Type: text/html\r\n" +
|
||||
"\r\n" +
|
||||
"Unit test of ActionFileUploadInterceptor" +
|
||||
"\r\n" +
|
||||
"-----1234\r\n" +
|
||||
"Content-Disposition: form-data; name=\"normalFormField1\"\r\n" +
|
||||
"\r\n" +
|
||||
"normal field 1" +
|
||||
"\r\n" +
|
||||
"-----1234\r\n" +
|
||||
"Content-Disposition: form-data; name=\"normalFormField2\"\r\n" +
|
||||
"\r\n" +
|
||||
"normal field 2" +
|
||||
"\r\n" +
|
||||
"-----1234--\r\n");
|
||||
request.setContent(content.getBytes(StandardCharsets.US_ASCII));
|
||||
|
||||
MyFileUploadAction action = new MyFileUploadAction();
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("success");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
ActionContext.getContext().withServletRequest(createMultipartRequest(2000, 2000, 5, 100));
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertFalse(action.hasErrors());
|
||||
|
||||
List<UploadedFile> files = action.getUploadFiles();
|
||||
|
||||
assertNotNull(files);
|
||||
assertEquals(1, files.size());
|
||||
assertEquals("text/html", files.get(0).getContentType());
|
||||
assertNotNull("deleteme.txt", files.get(0).getOriginalName());
|
||||
|
||||
// Confirm normalFormField1, normalFormField2 were processed by the MultiPartRequestWrapper.
|
||||
HttpServletRequest invocationServletRequest = mai.getInvocationContext().getServletRequest();
|
||||
assertTrue("invocation servelt request is not a MultiPartRequestWrapper ?", invocationServletRequest instanceof MultiPartRequestWrapper);
|
||||
MultiPartRequestWrapper multipartRequestWrapper = (MultiPartRequestWrapper) invocationServletRequest;
|
||||
assertNotNull("normalFormField1 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField1"));
|
||||
assertNotNull("normalFormField2 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField2"));
|
||||
}
|
||||
|
||||
public void testSuccessUploadOfATextFileMultipartRequestWithNormalFieldsNoMaxParamsSet() throws Exception {
|
||||
request.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
request.setMethod("post");
|
||||
request.addHeader("Content-type", "multipart/form-data; boundary=---1234");
|
||||
|
||||
// inspired by the unit tests for jakarta commons fileupload
|
||||
String content = ("-----1234\r\n" +
|
||||
"Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" +
|
||||
"Content-Type: text/html\r\n" +
|
||||
"\r\n" +
|
||||
"Unit test of ActionFileUploadInterceptor" +
|
||||
"\r\n" +
|
||||
"-----1234\r\n" +
|
||||
"Content-Disposition: form-data; name=\"normalFormField1\"\r\n" +
|
||||
"\r\n" +
|
||||
"normal field 1" +
|
||||
"\r\n" +
|
||||
"-----1234\r\n" +
|
||||
"Content-Disposition: form-data; name=\"normalFormField2\"\r\n" +
|
||||
"\r\n" +
|
||||
"normal field 2" +
|
||||
"\r\n" +
|
||||
"-----1234--\r\n");
|
||||
request.setContent(content.getBytes(StandardCharsets.US_ASCII));
|
||||
|
||||
MyFileUploadAction action = new MyFileUploadAction();
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
mai.setAction(action);
|
||||
mai.setResultCode("success");
|
||||
mai.setInvocationContext(ActionContext.getContext());
|
||||
ActionContext.getContext().withServletRequest(createMultipartRequestNoMaxParamsSet());
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertFalse(action.hasErrors());
|
||||
|
||||
List<UploadedFile> files = action.getUploadFiles();
|
||||
|
||||
assertNotNull(files);
|
||||
assertEquals(1, files.size());
|
||||
assertEquals("text/html", files.get(0).getContentType());
|
||||
assertNotNull("deleteme.txt", files.get(0).getOriginalName());
|
||||
|
||||
// Confirm normalFormField1, normalFormField2 were processed by the MultiPartRequestWrapper.
|
||||
HttpServletRequest invocationServletRequest = mai.getInvocationContext().getServletRequest();
|
||||
assertTrue("invocation servelt request is not a MultiPartRequestWrapper ?", invocationServletRequest instanceof MultiPartRequestWrapper);
|
||||
MultiPartRequestWrapper multipartRequestWrapper = (MultiPartRequestWrapper) invocationServletRequest;
|
||||
assertNotNull("normalFormField1 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField1"));
|
||||
assertNotNull("normalFormField2 missing from MultiPartRequestWrapper parameters ?", multipartRequestWrapper.getParameter("normalFormField2"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether with multiple files sent with the same name, the ones with forbiddenTypes (see
|
||||
* ActionFileUploadInterceptor.setAllowedTypes(...) ) are sorted out.
|
||||
@@ -614,6 +752,11 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
return new MultiPartRequestWrapper(jak, request, tempDir.getAbsolutePath(), new DefaultLocaleProvider());
|
||||
}
|
||||
|
||||
private MultiPartRequestWrapper createMultipartRequestNoMaxParamsSet() {
|
||||
JakartaMultiPartRequest jak = new JakartaMultiPartRequest();
|
||||
return new MultiPartRequestWrapper(jak, request, tempDir.getAbsolutePath(), new DefaultLocaleProvider());
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
request = new MockHttpServletRequest();
|
||||
@@ -632,6 +775,9 @@ public class ActionFileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
public static class MyFileUploadAction extends ActionSupport implements UploadedFilesAware {
|
||||
private List<UploadedFile> uploadedFiles;
|
||||
|
||||
// Note: We do not currently need fields/getters/setters for normalFormField1, normalFormField2 since
|
||||
// the upload interceptor only prepares the normal field parameters.
|
||||
|
||||
@Override
|
||||
public void withUploadedFiles(List<UploadedFile> uploadedFiles) {
|
||||
this.uploadedFiles = uploadedFiles;
|
||||
|
||||
@@ -403,6 +403,7 @@ public class ActionTagTest extends AbstractTagTest {
|
||||
|
||||
public void testExecuteButResetReturnSameInvocation() throws Exception {
|
||||
Mock mockActionInv = new Mock(ActionInvocation.class);
|
||||
mockActionInv.matchAndReturn("invoke", "TEST");
|
||||
ActionTag tag = new ActionTag();
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setNamespace("");
|
||||
@@ -419,7 +420,7 @@ public class ActionTagTest extends AbstractTagTest {
|
||||
ActionComponent component = (ActionComponent) tag.getComponent();
|
||||
|
||||
tag.doEndTag();
|
||||
assertSame(oldInvocation, ActionContext.getContext().getActionInvocation());
|
||||
assertEquals(oldInvocation.invoke(), ActionContext.getContext().getActionInvocation().invoke());
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
ActionTag freshTag = new ActionTag();
|
||||
@@ -432,6 +433,7 @@ public class ActionTagTest extends AbstractTagTest {
|
||||
|
||||
public void testExecuteButResetReturnSameInvocation_clearTagStateSet() throws Exception {
|
||||
Mock mockActionInv = new Mock(ActionInvocation.class);
|
||||
mockActionInv.matchAndReturn("invoke", "TEST");
|
||||
ActionTag tag = new ActionTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setPageContext(pageContext);
|
||||
@@ -450,7 +452,7 @@ public class ActionTagTest extends AbstractTagTest {
|
||||
ActionComponent component = (ActionComponent) tag.getComponent();
|
||||
|
||||
tag.doEndTag();
|
||||
assertTrue(oldInvocation == ActionContext.getContext().getActionInvocation());
|
||||
assertEquals(oldInvocation.invoke(), ActionContext.getContext().getActionInvocation().invoke());
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
ActionTag freshTag = new ActionTag();
|
||||
|
||||
+1
-1
@@ -20,7 +20,6 @@ package org.apache.struts.beanvalidation.validation.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
|
||||
@@ -33,6 +32,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts.beanvalidation.constraints.ValidationGroup;
|
||||
import org.apache.struts.beanvalidation.validation.constant.ValidatorConstants;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
import org.apache.struts2.interceptor.validation.SkipValidation;
|
||||
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
|
||||
@@ -20,7 +20,6 @@ package org.apache.struts2.json;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
@@ -29,6 +28,7 @@ import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.json.smd.SMDGenerator;
|
||||
|
||||
|
||||
@@ -20,13 +20,13 @@ package org.apache.struts2.json;
|
||||
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.ActionProxyFactory;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.interceptor.annotations.After;
|
||||
import com.opensymphony.xwork2.interceptor.annotations.Before;
|
||||
import jakarta.servlet.ServletException;
|
||||
@@ -35,6 +34,7 @@ import org.apache.struts2.dispatcher.Dispatcher;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapper;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
import org.apache.struts2.util.StrutsTestCaseHelper;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
package org.apache.struts2.rest;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.rest.handler.ContentTypeHandler;
|
||||
|
||||
|
||||
@@ -18,19 +18,23 @@
|
||||
*/
|
||||
package org.apache.struts2.rest;
|
||||
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.DefaultActionInvocation;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.result.HttpHeaderResult;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
import org.apache.struts2.rest.handler.ContentTypeHandler;
|
||||
import org.apache.struts2.rest.handler.HtmlHandler;
|
||||
import org.apache.struts2.result.HttpHeaderResult;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -74,7 +78,7 @@ public class RestActionInvocation extends DefaultActionInvocation {
|
||||
/**
|
||||
* If set to true (by default) blocks returning content from any other methods than GET,
|
||||
* if set to false, the content can be returned for any kind of method
|
||||
*
|
||||
*
|
||||
* @param restrictToGet true or false
|
||||
*/
|
||||
@Inject(value = RestConstants.REST_CONTENT_RESTRICT_TO_GET, required = false)
|
||||
|
||||
@@ -23,10 +23,10 @@ import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
package org.apache.struts2.rest.handler;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import com.thoughtworks.xstream.io.xml.StaxDriver;
|
||||
import com.thoughtworks.xstream.security.ArrayTypePermission;
|
||||
@@ -29,6 +28,7 @@ import com.thoughtworks.xstream.security.PrimitiveTypePermission;
|
||||
import com.thoughtworks.xstream.security.TypePermission;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
import org.apache.struts2.rest.handler.xstream.XStreamAllowedClassNames;
|
||||
import org.apache.struts2.rest.handler.xstream.XStreamAllowedClasses;
|
||||
import org.apache.struts2.rest.handler.xstream.XStreamPermissionProvider;
|
||||
|
||||
@@ -110,13 +110,13 @@
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
|
||||
<!-- dependency versions in alphanumeric order -->
|
||||
<asm.version>9.7</asm.version>
|
||||
<asm.version>9.7.1</asm.version>
|
||||
<byte-buddy.version>1.14.11</byte-buddy.version>
|
||||
<freemarker.version>2.3.33</freemarker.version>
|
||||
<hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
|
||||
<jackson.version>2.18.0</jackson.version>
|
||||
<log4j2.version>2.24.1</log4j2.version>
|
||||
<maven-surefire-plugin.version>3.5.0</maven-surefire-plugin.version>
|
||||
<maven-surefire-plugin.version>3.5.1</maven-surefire-plugin.version>
|
||||
<mockito.version>5.8.0</mockito.version>
|
||||
<ognl.version>3.3.5</ognl.version>
|
||||
<slf4j.version>2.0.16</slf4j.version>
|
||||
@@ -412,7 +412,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.doxia</groupId>
|
||||
<artifactId>doxia-core</artifactId>
|
||||
<version>1.12.0</version>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.doxia</groupId>
|
||||
@@ -805,7 +805,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.15.0</version>
|
||||
<version>3.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
|
||||
Reference in New Issue
Block a user