From d9f29b3d57d9f031b2ebbc01fc85e653038135c7 Mon Sep 17 00:00:00 2001 From: Patrick Lightbody Date: Mon, 22 May 2006 13:47:57 +0000 Subject: [PATCH] bob's latest API git-svn-id: https://svn.apache.org/repos/asf/struts/action2/trunk@408662 13f79535-47bb-0310-9956-ffa450edef68 --- action-api/pom.xml | 3 +- .../org/apache/struts/action2/ErrorAware.java | 45 ----- .../apache/struts/action2/MessageAware.java | 14 +- .../org/apache/struts/action2/Messages.java | 174 +++++++++++++++--- .../apache/struts/action2/Validatable.java | 3 +- .../attribute/ApplicationAttribute.java | 10 +- .../action2/attribute/RequestAttribute.java | 10 +- .../action2/attribute/SessionAttribute.java | 10 +- .../apache/struts/action2/package-info.java | 2 +- .../struts/action2/spi/ActionContext.java | 59 ++++++ .../struts/action2/spi/Interceptor.java | 4 +- .../apache/struts/action2/spi/Request.java | 126 ------------- .../struts/action2/spi/RequestAware.java | 16 -- .../struts/action2/spi/RequestContext.java | 106 +++++++++++ .../action2/spi/RequestContextAware.java | 17 ++ .../org/apache/struts/action2/spi/Result.java | 4 +- .../action2/spi/ThreadLocalRequest.java | 54 ------ .../spi/ThreadLocalRequestContext.java | 54 ++++++ .../struts/action2/spi/package-info.java | 2 +- .../action2/spi/ThreadLocalRequestTest.java | 16 +- 20 files changed, 426 insertions(+), 303 deletions(-) create mode 100644 action-api/src/main/java/org/apache/struts/action2/spi/ActionContext.java create mode 100644 action-api/src/main/java/org/apache/struts/action2/spi/RequestContext.java create mode 100644 action-api/src/main/java/org/apache/struts/action2/spi/RequestContextAware.java create mode 100644 action-api/src/main/java/org/apache/struts/action2/spi/ThreadLocalRequestContext.java diff --git a/action-api/pom.xml b/action-api/pom.xml index e8042bc78..298f6e590 100644 --- a/action-api/pom.xml +++ b/action-api/pom.xml @@ -16,18 +16,19 @@ javax.servlet servlet-api 2.4 - provided junit junit test + true easymock easymock test + 2.0 diff --git a/action-api/src/main/java/org/apache/struts/action2/ErrorAware.java b/action-api/src/main/java/org/apache/struts/action2/ErrorAware.java index 59897b22f..e69de29bb 100644 --- a/action-api/src/main/java/org/apache/struts/action2/ErrorAware.java +++ b/action-api/src/main/java/org/apache/struts/action2/ErrorAware.java @@ -1,45 +0,0 @@ -package org.apache.struts.action2; - -/** - * Implemented by actions that may need to record error messages. For example: - * - *
- *   static import ResultNames.*;
- *
- *   public class SetName implements ErrorAware {
- *
- *     Messages errors;
- *     String name;
- *
- *     public String execute() {
- *       if ("".equals(name) {
- *         errors.add("name.required");
- *         return INPUT;
- *       }
- *
- *       ...
- *       return SUCCESS;
- *     }
- *
- *     public void setErrors(Messages errors) {
- *       this.errors = errors;
- *     }
- *
- *     public void setName(String name) {
- *       this.name = name;
- *     }
- *   }
- * 
- * - * @see MessageAware - * @author crazybob@google.com (Bob Lee) - */ -public interface ErrorAware { - - /** - * Sets error messages. - * - * @param errors error messages - */ - void setErrors(Messages errors); -} diff --git a/action-api/src/main/java/org/apache/struts/action2/MessageAware.java b/action-api/src/main/java/org/apache/struts/action2/MessageAware.java index 1c7016fe1..7b2944f5f 100644 --- a/action-api/src/main/java/org/apache/struts/action2/MessageAware.java +++ b/action-api/src/main/java/org/apache/struts/action2/MessageAware.java @@ -1,27 +1,33 @@ package org.apache.struts.action2; /** - * Implemented by actions that may need to record messages. + * Implemented by actions which may need to record errors or messages. * *
  *   static import ResultNames.*;
  *
- *   public class Welcome implements MessageAware {
+ *   public class SetName implements MessageAware {
  *
  *     Messages messages;
+ *     String name;
  *
  *     public String execute() {
- *       messages.add("welcome");
  *       return SUCCESS;
  *     }
  *
+ *     public void setName(String name) {
+ *       if ("".equals(name))
+ *         messages.forField("name").addError("name.required");
+ *
+ *       this.name = name;
+ *     }
+ *
  *     public void setMessages(Messages messages) {
  *       this.messages = messages;
  *     }
  *   }
  * 
* - * @see ErrorAware * @author crazybob@google.com (Bob Lee) */ public interface MessageAware { diff --git a/action-api/src/main/java/org/apache/struts/action2/Messages.java b/action-api/src/main/java/org/apache/struts/action2/Messages.java index a9e60da04..877fa1372 100644 --- a/action-api/src/main/java/org/apache/struts/action2/Messages.java +++ b/action-api/src/main/java/org/apache/struts/action2/Messages.java @@ -2,71 +2,193 @@ package org.apache.struts.action2; import java.util.List; import java.util.Set; +import java.util.Map; /** - * Request and field-scoped messages or errors. Uses keys instead of actual messages to decouple code from messages. - * Messages may come from multiple actions and interceptors. + * Collection of messages. Supports nesting messages by field name. + * + *

Uses keys when adding instead of actual messages to decouple code from messages. * * @author crazybob@google.com (Bob Lee) */ public interface Messages { /** - * Adds request-scoped message. + * Message severity. + */ + public enum Severity { + + /** + * Informational messages. + */ + INFO, + + /** + * Warning messages. + */ + WARN, + + /** + * Error messages. + */ + ERROR, + } + + /** + * Gets nested messages for the given field. + * + *

Supports dot notation to represent nesting. For example: + * + *

+     * messages.forField("foo").forField("bar") == messages.forField("foo.bar")
+     * 
+ * + * @param fieldName name of the field + * @return nested {@code Messages} for given field name + */ + Messages forField(String fieldName); + + /** + * Gets map of field name to messages for that field. + * + * @return map of field name to {@code Messages} + */ + Map forFields(); + + /** + * Adds informational message. * * @param key message key + * @see Severity.INFO */ - void add(String key); + void addInformation(String key); + + /** + * Adds informational message. + * + * @param key message key + * @param arguments message arguments + * @see Severity.INFO + */ + void addInformation(String key, Object... arguments); + + /** + * Adds warning message. + * + * @param key message key + * @see Severity.WARN + */ + void addWarning(String key); + + /** + * Adds warning message. + * + * @param key message key + * @param arguments message arguments + * @see Severity.WARN + */ + void addWarning(String key, Object... arguments); + + /** + * Adds error message. + * + * @param key message key + * @see Severity.ERROR + */ + void addError(String key); + + /** + * Adds error message. + * + * @param key message key + * @param arguments message arguments + * @see Severity.ERROR + */ + void addError(String key, Object... arguments); + + /** + * Adds message. + * + * @param severity message severity + * @param key message key + */ + void add(Severity severity, String key); /** * Adds request-scoped message. * + * @param severity message severity * @param key message key * @param arguments message arguments */ - void add(String key, Object... arguments); + void add(Severity severity, String key, Object... arguments); /** - * Adds field-scoped message. + * Gets set of severities for which this {@code Messages} instance has messages. Not recursive. * - * @param fieldName name of field to attach message to - * @param key message key + * @return unmodifiable set of {@link Severity} sorted from least to most severe */ - void add(String fieldName, String key); + Set getSeverities(); /** - * Adds field-scoped message. + * Gets message strings for the given severity. Not recursive. * - * @param fieldName name of field to attach message to - * @param key message key - * @param arguments message arguments + * @param severity message severity + * @return unmodifiable list of messages */ - void add(String fieldName, String key, Object... arguments); + List forSeverity(Severity severity); /** - * Gets request-scoped messages. + * Gets error message strings for this {@code Messages} instance. Not recursive. * - * @return unmodifiable list of messages for this request. + * @return unmodifiable list of messages */ - List forRequest(); + List getErrors(); /** - * Gets field-scoped messages. + * Gets error message strings for this {@code Messages} instance. Not recursive. * - * @param fieldName field name - * @return unmodifiable list of messages for the given field name. + * @return unmodifiable list of messages */ - List forField(String fieldName); + List getWarnings(); /** - * Gets names of fields which have messages attached. + * Gets informational message strings for this {@code Messages} instance. Not recursive. * - * @return unmodifiable set of field names with messages attached. + * @return unmodifiable list of messages */ - Set getFieldNames(); + List getInformation(); /** - * Returns true if no request or field-scoped messages have been added. + * Returns true if this or a nested {@code Messages} instance has error messages. + * + * @see Severity.ERROR + */ + boolean hasErrors(); + + /** + * Returns true if this or a nested {@code Messages} instance has warning messages. + * + * @see Severity.WARN + */ + boolean hasWarnings(); + + /** + * Returns true if this or a nested {@code Messages} instance has informational messages. + * + * @see Severity.INFO + */ + boolean hasInformation(); + + /** + * Returns true if this and all nested {@code Messages} instances have no messages. */ boolean isEmpty(); -} + + /** + * Returns true if this and all nested {@code Messages} instances have no messages for the given severity. + * + * @param severity message severity + */ + boolean isEmpty(Severity severity); +} \ No newline at end of file diff --git a/action-api/src/main/java/org/apache/struts/action2/Validatable.java b/action-api/src/main/java/org/apache/struts/action2/Validatable.java index d681fc61a..90e9fbbe2 100644 --- a/action-api/src/main/java/org/apache/struts/action2/Validatable.java +++ b/action-api/src/main/java/org/apache/struts/action2/Validatable.java @@ -4,10 +4,9 @@ package org.apache.struts.action2; * Implemented by actions which wish to execute some validation logic before their action method. Useful for * cross-field validations. * - * @see ErrorAware * @author crazybob@google.com (Bob Lee) */ -public interface Validatable { +public interface Validatable extends MessageAware { /** * Validates input. Executes before action method. diff --git a/action-api/src/main/java/org/apache/struts/action2/attribute/ApplicationAttribute.java b/action-api/src/main/java/org/apache/struts/action2/attribute/ApplicationAttribute.java index eb8b800fc..db8ab2e73 100644 --- a/action-api/src/main/java/org/apache/struts/action2/attribute/ApplicationAttribute.java +++ b/action-api/src/main/java/org/apache/struts/action2/attribute/ApplicationAttribute.java @@ -1,7 +1,7 @@ package org.apache.struts.action2.attribute; -import org.apache.struts.action2.spi.Request; -import org.apache.struts.action2.spi.ThreadLocalRequest; +import org.apache.struts.action2.spi.RequestContext; +import org.apache.struts.action2.spi.ThreadLocalRequestContext; /** * A servlet context attribute. Synchronizes on the underlying {@code ServletContext} instance. @@ -20,9 +20,9 @@ public class ApplicationAttribute extends AbstractAttribute { } T execute(UnitOfWork unitOfWork) { - Request request = ThreadLocalRequest.get(); - synchronized (request.getServletContext()) { - return unitOfWork.execute(request.getApplicationMap()); + RequestContext requestContext = ThreadLocalRequestContext.get(); + synchronized (requestContext.getServletContext()) { + return unitOfWork.execute(requestContext.getApplicationMap()); } } } diff --git a/action-api/src/main/java/org/apache/struts/action2/attribute/RequestAttribute.java b/action-api/src/main/java/org/apache/struts/action2/attribute/RequestAttribute.java index a2a535788..1e7c2fbe8 100644 --- a/action-api/src/main/java/org/apache/struts/action2/attribute/RequestAttribute.java +++ b/action-api/src/main/java/org/apache/struts/action2/attribute/RequestAttribute.java @@ -1,7 +1,7 @@ package org.apache.struts.action2.attribute; -import org.apache.struts.action2.spi.Request; -import org.apache.struts.action2.spi.ThreadLocalRequest; +import org.apache.struts.action2.spi.RequestContext; +import org.apache.struts.action2.spi.ThreadLocalRequestContext; /** * A request attribute. Synchronizes on the underlying {@code HttpServletRequest} instance. @@ -20,9 +20,9 @@ public class RequestAttribute extends AbstractAttribute { } T execute(UnitOfWork unitOfWork) { - Request request = ThreadLocalRequest.get(); - synchronized (request.getServletRequest()) { - return unitOfWork.execute(request.getAttributeMap()); + RequestContext requestContext = ThreadLocalRequestContext.get(); + synchronized (requestContext.getServletRequest()) { + return unitOfWork.execute(requestContext.getAttributeMap()); } } } diff --git a/action-api/src/main/java/org/apache/struts/action2/attribute/SessionAttribute.java b/action-api/src/main/java/org/apache/struts/action2/attribute/SessionAttribute.java index 14f3caae0..65c016db4 100644 --- a/action-api/src/main/java/org/apache/struts/action2/attribute/SessionAttribute.java +++ b/action-api/src/main/java/org/apache/struts/action2/attribute/SessionAttribute.java @@ -1,7 +1,7 @@ package org.apache.struts.action2.attribute; -import org.apache.struts.action2.spi.Request; -import org.apache.struts.action2.spi.ThreadLocalRequest; +import org.apache.struts.action2.spi.RequestContext; +import org.apache.struts.action2.spi.ThreadLocalRequestContext; /** * A session attribute. Synchronizes on the underlying {@code HttpSession}. @@ -20,9 +20,9 @@ public class SessionAttribute extends AbstractAttribute { } T execute(UnitOfWork unitOfWork) { - Request request = ThreadLocalRequest.get(); - synchronized (request.getServletRequest().getSession()) { - return unitOfWork.execute(request.getSessionMap()); + RequestContext requestContext = ThreadLocalRequestContext.get(); + synchronized (requestContext.getServletRequest().getSession()) { + return unitOfWork.execute(requestContext.getSessionMap()); } } } diff --git a/action-api/src/main/java/org/apache/struts/action2/package-info.java b/action-api/src/main/java/org/apache/struts/action2/package-info.java index 42c770752..b1d7ec369 100644 --- a/action-api/src/main/java/org/apache/struts/action2/package-info.java +++ b/action-api/src/main/java/org/apache/struts/action2/package-info.java @@ -1,4 +1,4 @@ /** - * Struts Action 2.0 user API. + * Struts Action 2.0 user API */ package org.apache.struts.action2; \ No newline at end of file diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/ActionContext.java b/action-api/src/main/java/org/apache/struts/action2/spi/ActionContext.java new file mode 100644 index 000000000..570359a97 --- /dev/null +++ b/action-api/src/main/java/org/apache/struts/action2/spi/ActionContext.java @@ -0,0 +1,59 @@ +package org.apache.struts.action2.spi; + +import java.lang.reflect.Method; + +/** + * Context of an action execution. + * + * @author crazybob@google.com (Bob Lee) + */ +public interface ActionContext { + + /** + * Gets action instance. + */ + Object getAction(); + + /** + * Gets action method. + */ + Method getMethod(); + + /** + * Gets action name. + */ + String getActionName(); + + /** + * Gets the path for the action's namespace. + */ + String getNamespacePath(); + + /** + * Gets the {@link Result} instance for the action. + * + * @return {@link Result} instance or {@code null} if we don't have a result yet. + */ + Result getResult(); + + /** + * Adds a result interceptor for the action. Enables executing code before and after a result, executing an + * alternate result, etc. + */ + void addResultInterceptor(Result interceptor); + + /** + * Gets context of action which chained to us. + * + * @return context of previous action or {@code null} if this is the first action in the chain + */ + ActionContext getPrevious(); + + /** + * Gets context of action which this action chained to. + * + * @return context of next action or {@code null} if we haven't chained to another action yet or this is the last + * action in the chain. + */ + ActionContext getNext(); +} diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/Interceptor.java b/action-api/src/main/java/org/apache/struts/action2/spi/Interceptor.java index d0c693d61..99c3f3d95 100644 --- a/action-api/src/main/java/org/apache/struts/action2/spi/Interceptor.java +++ b/action-api/src/main/java/org/apache/struts/action2/spi/Interceptor.java @@ -10,7 +10,7 @@ public interface Interceptor { /** * Intercepts an action request. * - * @param request current request + * @param requestContext current request context */ - String intercept(Request request) throws Exception; + String intercept(RequestContext requestContext) throws Exception; } diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/Request.java b/action-api/src/main/java/org/apache/struts/action2/spi/Request.java index 61fe3ecc9..e69de29bb 100644 --- a/action-api/src/main/java/org/apache/struts/action2/spi/Request.java +++ b/action-api/src/main/java/org/apache/struts/action2/spi/Request.java @@ -1,126 +0,0 @@ -package org.apache.struts.action2.spi; - -import org.apache.struts.action2.Messages; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.ServletContext; -import java.util.Locale; -import java.util.Map; -import java.util.List; -import java.lang.reflect.Method; - -/** - * A Struts request. A single request may span multiple actions with action chaining. - * - * @author crazybob@google.com (Bob Lee) - */ -public interface Request { - - /** - * Gets current action instance. - */ - Object getAction(); - - /** - * Gets current action method. - */ - Method getMethod(); - - /** - * Gets current action name. - */ - String getActionName(); - - /** - * Gets the path for the current action's namespace. - */ - String getNamespacePath(); - - /** - * Gets the {@link Result} instance for the current action. - * - * @return {@link Result} instance or {@code null} if we don't have a result yet. - */ - Result getResult(); - - /** - * Adds a result interceptor for the current action. Enables executing code before and after a result, executing - * an alternate result, etc. - */ - void addResultInterceptor(Result interceptor); - - /** - * Gets map of request parameters. - */ - Map getParameterMap(); - - /** - * Gets map of request attributes. - */ - Map getAttributeMap(); - - /** - * Gets map of session attributes. - */ - Map getSessionMap(); - - /** - * Gets map of application (servlet context) attributes. - */ - Map getApplicationMap(); - - /** - * Finds cookies with the given name, - */ - List findCookiesForName(String name); - - /** - * Gets locale. - */ - Locale getLocale(); - - /** - * Sets locale. Stores the locale in the session for future requests. - */ - void setLocale(Locale locale); - - /** - * Gets messages. - */ - Messages getMessages(); - - /** - * Gets error messages. - */ - Messages getErrors(); - - /** - * Gets the servlet request. - */ - HttpServletRequest getServletRequest(); - - /** - * Gets the servlet response. - */ - HttpServletResponse getServletResponse(); - - /** - * Gets the servlet context. - */ - ServletContext getServletContext(); - - /** - * Gets the value stack. - */ - ValueStack getValueStack(); - - /** - * Invokes the next interceptor or the action method if no more interceptors remain. - * - * @return result name - * @throws IllegalStateException if already invoked or called from the action - */ - String proceed() throws Exception; -} diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/RequestAware.java b/action-api/src/main/java/org/apache/struts/action2/spi/RequestAware.java index 8386ab6ce..e69de29bb 100644 --- a/action-api/src/main/java/org/apache/struts/action2/spi/RequestAware.java +++ b/action-api/src/main/java/org/apache/struts/action2/spi/RequestAware.java @@ -1,16 +0,0 @@ -package org.apache.struts.action2.spi; - -/** - * Implemented by actions that need access to the current {@link Request}. Use judiciously. - * - * @author crazybob@google.com (Bob Lee) - */ -public interface RequestAware { - - /** - * Sets {@link Request}. - * - * @param request - */ - void setRequest(Request request); -} diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/RequestContext.java b/action-api/src/main/java/org/apache/struts/action2/spi/RequestContext.java new file mode 100644 index 000000000..8b40cfa1a --- /dev/null +++ b/action-api/src/main/java/org/apache/struts/action2/spi/RequestContext.java @@ -0,0 +1,106 @@ +package org.apache.struts.action2.spi; + +import org.apache.struts.action2.Messages; + +import javax.servlet.ServletContext; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** + * Request context. A single request may span multiple actions with action chaining. + * + * @author crazybob@google.com (Bob Lee) + */ +public interface RequestContext { + + /** + * Gets context of the currently executing action. + * + * @return current action context + */ + ActionContext getActionContext(); + + /** + * Convenience method. Equivalent to {@code getActionContext().getAction()}. + * + * @return currently executing action + */ + Object getAction(); + + /** + * Gets map of request parameters. + */ + Map getParameterMap(); + + /** + * Gets map of request attributes. + */ + Map getAttributeMap(); + + /** + * Gets map of session attributes. + */ + Map getSessionMap(); + + /** + * Gets map of application (servlet context) attributes. + */ + Map getApplicationMap(); + + /** + * Finds cookies with the given name, + */ + List findCookiesForName(String name); + + /** + * Gets locale. + */ + Locale getLocale(); + + /** + * Sets locale. Stores the locale in the session for future requests. + */ + void setLocale(Locale locale); + + /** + * Gets messages. + */ + Messages getMessages(); + + /** + * Gets error messages. + */ + Messages getErrors(); + + /** + * Gets the servlet request. + */ + HttpServletRequest getServletRequest(); + + /** + * Gets the servlet response. + */ + HttpServletResponse getServletResponse(); + + /** + * Gets the servlet context. + */ + ServletContext getServletContext(); + + /** + * Gets the value stack. + */ + ValueStack getValueStack(); + + /** + * Invokes the next interceptor or the action method if no more interceptors remain. + * + * @return result name + * @throws IllegalStateException if already invoked or called from the action + */ + String proceed() throws Exception; +} diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/RequestContextAware.java b/action-api/src/main/java/org/apache/struts/action2/spi/RequestContextAware.java new file mode 100644 index 000000000..d192c5ca5 --- /dev/null +++ b/action-api/src/main/java/org/apache/struts/action2/spi/RequestContextAware.java @@ -0,0 +1,17 @@ +package org.apache.struts.action2.spi; + +/** + * Implemented by actions that need access to the current {@link org.apache.struts.action2.spi.RequestContext}. Use + * judiciously. + * + * @author crazybob@google.com (Bob Lee) + */ +public interface RequestContextAware { + + /** + * Sets {@link org.apache.struts.action2.spi.RequestContext}. + * + * @param requestContext + */ + void setRequestContext(RequestContext requestContext); +} diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/Result.java b/action-api/src/main/java/org/apache/struts/action2/spi/Result.java index 4273495a4..08021fa01 100644 --- a/action-api/src/main/java/org/apache/struts/action2/spi/Result.java +++ b/action-api/src/main/java/org/apache/struts/action2/spi/Result.java @@ -10,7 +10,7 @@ public interface Result { /** * Executes result. * - * @param request + * @param requestContext */ - void execute(Request request) throws Exception; + void execute(RequestContext requestContext) throws Exception; } diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/ThreadLocalRequest.java b/action-api/src/main/java/org/apache/struts/action2/spi/ThreadLocalRequest.java index d979efce4..e69de29bb 100644 --- a/action-api/src/main/java/org/apache/struts/action2/spi/ThreadLocalRequest.java +++ b/action-api/src/main/java/org/apache/struts/action2/spi/ThreadLocalRequest.java @@ -1,54 +0,0 @@ -package org.apache.struts.action2.spi; - -import java.util.concurrent.Callable; - -/** - * Provides a reference to the current {@link Request} for this thread. - * - *

Actions which spawn additional threads are responsible for setting this value if access to Struts from the - * additional thread is needed. - * - * @author crazybob@google.com (Bob Lee) - */ -public final class ThreadLocalRequest { - - static ThreadLocal threadLocalRequest = new ThreadLocal(); - - private ThreadLocalRequest() {} - - /** - * Sets {@link Request} for the current thread and invokes the provided {@link Callable}. Restores previous {@code - * Request} (if any) when finished. - * - * @param request for current thread - * @param callable - * @return result of {@code callable} - * @throws Exception from {@code callable} - */ - public static T setAndCall(Request request, Callable callable) throws Exception { - Request old = threadLocalRequest.get(); - try { - threadLocalRequest.set(request); - return callable.call(); - } finally { - if (old == null) - threadLocalRequest.remove(); - else - threadLocalRequest.set(old); - } - } - - /** - * Gets the {@link Request} for the current thread. - * - * @return request for current thread - * @throws IllegalStateException if no request has been set - */ - public static Request get() { - Request request = threadLocalRequest.get(); - if (request == null) { - throw new IllegalStateException(ThreadLocalRequest.class.getName() + " has not been set."); - } - return request; - } -} diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/ThreadLocalRequestContext.java b/action-api/src/main/java/org/apache/struts/action2/spi/ThreadLocalRequestContext.java new file mode 100644 index 000000000..4bc32074e --- /dev/null +++ b/action-api/src/main/java/org/apache/struts/action2/spi/ThreadLocalRequestContext.java @@ -0,0 +1,54 @@ +package org.apache.struts.action2.spi; + +import java.util.concurrent.Callable; + +/** + * Provides a reference to the current {@link RequestContext} for this thread. + * + *

Actions which spawn additional threads are responsible for setting this value if access to Struts from the + * additional thread is needed. + * + * @author crazybob@google.com (Bob Lee) + */ +public final class ThreadLocalRequestContext { + + static ThreadLocal threadLocalRequestContext = new ThreadLocal(); + + private ThreadLocalRequestContext() {} + + /** + * Sets {@link RequestContext} for the current thread and invokes the provided {@link Callable}. Restores previous + * {@code RequestContext} (if any) when finished. + * + * @param requestContext for current thread + * @param callable + * @return result of {@code callable} + * @throws Exception from {@code callable} + */ + public static T setAndCall(RequestContext requestContext, Callable callable) throws Exception { + RequestContext old = threadLocalRequestContext.get(); + try { + threadLocalRequestContext.set(requestContext); + return callable.call(); + } finally { + if (old == null) + threadLocalRequestContext.remove(); + else + threadLocalRequestContext.set(old); + } + } + + /** + * Gets the {@link RequestContext} for the current thread. + * + * @return request for current thread + * @throws IllegalStateException if no request has been set + */ + public static RequestContext get() { + RequestContext requestContext = threadLocalRequestContext.get(); + if (requestContext == null) { + throw new IllegalStateException(ThreadLocalRequestContext.class.getName() + " has not been set."); + } + return requestContext; + } +} diff --git a/action-api/src/main/java/org/apache/struts/action2/spi/package-info.java b/action-api/src/main/java/org/apache/struts/action2/spi/package-info.java index c8c35b618..58c4a632b 100644 --- a/action-api/src/main/java/org/apache/struts/action2/spi/package-info.java +++ b/action-api/src/main/java/org/apache/struts/action2/spi/package-info.java @@ -1,4 +1,4 @@ /** - * Struts Action 2.0 service provider API. + * Struts Action 2.0 service provider API */ package org.apache.struts.action2.spi; \ No newline at end of file diff --git a/action-api/src/test/java/org/apache/struts/action2/spi/ThreadLocalRequestTest.java b/action-api/src/test/java/org/apache/struts/action2/spi/ThreadLocalRequestTest.java index e0f7691fa..2e425ec5d 100644 --- a/action-api/src/test/java/org/apache/struts/action2/spi/ThreadLocalRequestTest.java +++ b/action-api/src/test/java/org/apache/struts/action2/spi/ThreadLocalRequestTest.java @@ -11,21 +11,21 @@ import java.util.concurrent.Callable; public class ThreadLocalRequestTest extends TestCase { public void testSetAndCall() throws Exception { - final Request r1 = createMock(Request.class); - final Request r2 = createMock(Request.class); + final RequestContext r1 = createMock(RequestContext.class); + final RequestContext r2 = createMock(RequestContext.class); ensureNotSet(); - String result = ThreadLocalRequest.setAndCall(r1, new Callable() { + String result = ThreadLocalRequestContext.setAndCall(r1, new Callable() { public String call() throws Exception { - assertSame(r1, ThreadLocalRequest.get()); - String result = ThreadLocalRequest.setAndCall(r2, new Callable() { + assertSame(r1, ThreadLocalRequestContext.get()); + String result = ThreadLocalRequestContext.setAndCall(r2, new Callable() { public String call() throws Exception { - assertSame(r2, ThreadLocalRequest.get()); + assertSame(r2, ThreadLocalRequestContext.get()); return "foo"; } }); - assertSame(r1, ThreadLocalRequest.get()); + assertSame(r1, ThreadLocalRequestContext.get()); return result; } }); @@ -37,7 +37,7 @@ public class ThreadLocalRequestTest extends TestCase { private void ensureNotSet() { try { - ThreadLocalRequest.get(); + ThreadLocalRequestContext.get(); fail(); } catch (IllegalStateException e) { /* ignore */ }