You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by cr...@apache.org on 2006/08/02 02:07:18 UTC

svn commit: r427807 - in /struts/struts2/trunk: api/src/main/java/org/apache/struts2/ api/src/main/java/org/apache/struts2/spi/ api/src/test/java/org/apache/struts2/spi/ core/ core/src/main/java/org/apache/struts2/dispatcher/ core/src/main/java/org/apa...

Author: crazybob
Date: Tue Aug  1 17:07:17 2006
New Revision: 427807

URL: http://svn.apache.org/viewvc?rev=427807&view=rev
Log:
Initial API implementation.

Added:
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ActionContextImpl.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/InterceptorAdapter.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/MessagesImpl.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/RequestContextImpl.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ResultAdapter.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxy.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxyFactory.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsObjectFactory.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ValueStackAdapter.java
    struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/
    struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/MessagesTest.java
    struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/RequestContextTest.java
Removed:
    struts/struts2/trunk/api/src/main/java/org/apache/struts2/spi/ThreadLocalRequestContext.java
    struts/struts2/trunk/api/src/test/java/org/apache/struts2/spi/ThreadLocalRequestTest.java
Modified:
    struts/struts2/trunk/api/src/main/java/org/apache/struts2/Messages.java
    struts/struts2/trunk/api/src/main/java/org/apache/struts2/spi/RequestContext.java
    struts/struts2/trunk/core/pom.xml
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java

Modified: struts/struts2/trunk/api/src/main/java/org/apache/struts2/Messages.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/api/src/main/java/org/apache/struts2/Messages.java?rev=427807&r1=427806&r2=427807&view=diff
==============================================================================
--- struts/struts2/trunk/api/src/main/java/org/apache/struts2/Messages.java (original)
+++ struts/struts2/trunk/api/src/main/java/org/apache/struts2/Messages.java Tue Aug  1 17:07:17 2006
@@ -13,6 +13,8 @@
  */
 public interface Messages {
 
+    // TODO: Use Object[] for args instead of String[].
+
     /**
      * Message severity.
      */
@@ -70,7 +72,7 @@
      * @param arguments message arguments
      * @see Severity.INFO
      */
-    void addInformation(String key, Object... arguments);
+    void addInformation(String key, String... arguments);
 
     /**
      * Adds warning message.
@@ -87,7 +89,7 @@
      * @param arguments message arguments
      * @see Severity.WARN
      */
-    void addWarning(String key, Object... arguments);
+    void addWarning(String key, String... arguments);
 
     /**
      * Adds error message.
@@ -104,7 +106,7 @@
      * @param arguments message arguments
      * @see Severity.ERROR
      */
-    void addError(String key, Object... arguments);
+    void addError(String key, String... arguments);
 
     /**
      * Adds message.
@@ -121,7 +123,7 @@
      * @param key message key
      * @param arguments message arguments
      */
-    void add(Severity severity, String key, Object... arguments);
+    void add(Severity severity, String key, String... arguments);
 
     /**
      * Gets set of severities for which this {@code Messages} instance has messages. Not recursive.

Modified: struts/struts2/trunk/api/src/main/java/org/apache/struts2/spi/RequestContext.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/api/src/main/java/org/apache/struts2/spi/RequestContext.java?rev=427807&r1=427806&r2=427807&view=diff
==============================================================================
--- struts/struts2/trunk/api/src/main/java/org/apache/struts2/spi/RequestContext.java (original)
+++ struts/struts2/trunk/api/src/main/java/org/apache/struts2/spi/RequestContext.java Tue Aug  1 17:07:17 2006
@@ -1,7 +1,6 @@
 package org.apache.struts2.spi;
 
 import org.apache.struts2.Messages;
-import org.apache.struts2.spi.ActionContext;
 
 import javax.servlet.ServletContext;
 import javax.servlet.http.Cookie;
@@ -71,11 +70,6 @@
      * Gets messages.
      */
     Messages getMessages();
-
-    /**
-     * Gets error messages.
-     */
-    Messages getErrors();
 
     /**
      * Gets the servlet request.

Modified: struts/struts2/trunk/core/pom.xml
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/pom.xml?rev=427807&r1=427806&r2=427807&view=diff
==============================================================================
--- struts/struts2/trunk/core/pom.xml (original)
+++ struts/struts2/trunk/core/pom.xml Tue Aug  1 17:07:17 2006
@@ -37,6 +37,12 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.struts</groupId>
+            <artifactId>struts2-api</artifactId>
+            <version>${pom.version}</version>
+        </dependency>
+        
+        <dependency>
             <groupId>freemarker</groupId>
             <artifactId>freemarker</artifactId>
             <version>2.3.4</version>

Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java?rev=427807&r1=427806&r2=427807&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java (original)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java Tue Aug  1 17:07:17 2006
@@ -18,14 +18,13 @@
 package org.apache.struts2.dispatcher;
 
 import com.opensymphony.xwork2.ActionContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
 import javax.servlet.*;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 
 /**
  * <!-- SNIPPET START: description -->

Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java?rev=427807&r1=427806&r2=427807&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java (original)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java Tue Aug  1 17:07:17 2006
@@ -17,24 +17,23 @@
  */
 package org.apache.struts2.dispatcher;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import com.opensymphony.util.ClassLoaderUtil;
+import com.opensymphony.util.FileManager;
+import com.opensymphony.xwork2.*;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationManager;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import com.opensymphony.xwork2.util.*;
+import com.opensymphony.xwork2.util.location.Location;
+import com.opensymphony.xwork2.util.location.LocationUtils;
+import freemarker.template.Template;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.StrutsConstants;
 import org.apache.struts2.StrutsStatics;
+import org.apache.struts2.impl.StrutsObjectFactory;
+import org.apache.struts2.impl.StrutsActionProxyFactory;
 import org.apache.struts2.config.Settings;
 import org.apache.struts2.config.StrutsXMLConfigurationProvider;
 import org.apache.struts2.dispatcher.mapper.ActionMapping;
@@ -45,25 +44,13 @@
 import org.apache.struts2.util.ObjectFactoryInitializable;
 import org.apache.struts2.views.freemarker.FreemarkerManager;
 
-import com.opensymphony.util.ClassLoaderUtil;
-import com.opensymphony.util.FileManager;
-import com.opensymphony.xwork2.ActionContext;
-import com.opensymphony.xwork2.ActionProxy;
-import com.opensymphony.xwork2.ActionProxyFactory;
-import com.opensymphony.xwork2.ObjectFactory;
-import com.opensymphony.xwork2.Result;
-import com.opensymphony.xwork2.config.ConfigurationException;
-import com.opensymphony.xwork2.config.ConfigurationManager;
-import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
-import com.opensymphony.xwork2.util.LocalizedTextUtil;
-import com.opensymphony.xwork2.util.ObjectTypeDeterminer;
-import com.opensymphony.xwork2.util.ObjectTypeDeterminerFactory;
-import com.opensymphony.xwork2.util.OgnlValueStack;
-import com.opensymphony.xwork2.util.XWorkContinuationConfig;
-import com.opensymphony.xwork2.util.location.Location;
-import com.opensymphony.xwork2.util.location.LocationUtils;
-
-import freemarker.template.Template;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
 
 /**
  * A utility class the actual dispatcher delegates most of its tasks to. Each instance
@@ -74,6 +61,13 @@
  * @see org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher
  */
 public class Dispatcher {
+
+    // Set Struts-specific factories.
+    static {
+        ObjectFactory.setObjectFactory(new StrutsObjectFactory());
+        ActionProxyFactory.setFactory(new StrutsActionProxyFactory());
+    }
+
     private static final Log LOG = LogFactory.getLog(Dispatcher.class);
 
     private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ActionContextImpl.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ActionContextImpl.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ActionContextImpl.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ActionContextImpl.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,63 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import org.apache.struts2.spi.ActionContext;
+import org.apache.struts2.spi.Result;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.ArrayList;
+
+public class ActionContextImpl implements ActionContext {
+
+    final ActionInvocation invocation;
+
+    public ActionContextImpl(ActionInvocation invocation) {
+        this.invocation = invocation;
+    }
+
+    public Object getAction() {
+        return invocation.getAction();
+    }
+
+    public Method getMethod() {
+        String methodName = invocation.getProxy().getMethod();
+        try {
+            return getAction().getClass().getMethod(methodName);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public String getActionName() {
+        return invocation.getProxy().getActionName();
+    }
+
+    public String getNamespacePath() {
+        return invocation.getProxy().getNamespace();
+    }
+
+    // TODO: Do something with these.
+    List<Result> resultInterceptors = new ArrayList<Result>();
+
+    public void addResultInterceptor(Result interceptor) {
+        resultInterceptors.add(interceptor);
+    }
+
+    public Result getResult() {
+        // TODO
+        throw new UnsupportedOperationException();
+    }
+
+    public ActionContext getPrevious() {
+        // TODO
+        throw new UnsupportedOperationException();
+    }
+
+    public ActionContext getNext() {
+        // TODO
+        throw new UnsupportedOperationException();
+    }
+}

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/InterceptorAdapter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/InterceptorAdapter.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/InterceptorAdapter.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/InterceptorAdapter.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,47 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import static org.apache.struts2.impl.RequestContextImpl.ILLEGAL_PROCEED;
+import com.opensymphony.xwork2.interceptor.Interceptor;
+import com.opensymphony.xwork2.ActionInvocation;
+
+import java.util.concurrent.Callable;
+
+public class InterceptorAdapter implements Interceptor {
+
+    final org.apache.struts2.spi.Interceptor delegate;
+
+    public InterceptorAdapter(org.apache.struts2.spi.Interceptor delegate) {
+        this.delegate = delegate;
+    }
+
+    public String intercept(final ActionInvocation invocation) throws Exception {
+        final RequestContextImpl requestContext = RequestContextImpl.get();
+
+        // Save the existing proceed implementation so we can restore it later.
+        Callable<String> previous = requestContext.getProceed();
+
+        requestContext.setProceed(new Callable<String>() {
+            public String call() throws Exception {
+                // This proceed implementation is no longer valid past this point.
+                requestContext.setProceed(ILLEGAL_PROCEED);
+                try {
+                    return invocation.invoke();
+                } finally {
+                    // We're valid again.
+                    requestContext.setProceed(this);
+                }
+            }
+        });
+
+        try {
+            return delegate.intercept(requestContext);
+        } finally {
+            requestContext.setProceed(previous);
+        }
+    }
+
+    public void destroy() {}
+    public void init() {}
+}

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/MessagesImpl.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/MessagesImpl.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/MessagesImpl.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/MessagesImpl.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,126 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import com.opensymphony.xwork2.TextProvider;
+import com.opensymphony.xwork2.DefaultTextProvider;
+import org.apache.struts2.Messages;
+
+import java.util.*;
+
+public class MessagesImpl implements Messages {
+
+    final TextProvider textProvider = DefaultTextProvider.INSTANCE;
+    Map<String, Messages> fieldMap = new HashMap<String, Messages>();
+    Map<Severity, List<String>> severityMap = new EnumMap<Severity, List<String>>(Severity.class);
+
+    public Messages forField(String fieldName) {
+        Messages forField = fieldMap.get(fieldName);
+        if (forField == null) {
+            forField = new MessagesImpl();
+            fieldMap.put(fieldName, forField);
+        }
+        return forField;
+    }
+
+    public Map<String, Messages> forFields() {
+        return fieldMap;
+    }
+
+    public void addInformation(String key) {
+        forSeverity(Severity.INFO).add(textProvider.getText(key));
+    }
+
+    public void addInformation(String key, String... arguments) {
+        forSeverity(Severity.INFO).add(textProvider.getText(key, arguments));
+    }
+
+    public void addWarning(String key) {
+        forSeverity(Severity.WARN).add(textProvider.getText(key));
+    }
+
+    public void addWarning(String key, String... arguments) {
+        forSeverity(Severity.WARN).add(textProvider.getText(key, arguments));
+    }
+
+    public void addError(String key) {
+        forSeverity(Severity.ERROR).add(textProvider.getText(key));
+    }
+
+    public void addError(String key, String... arguments) {
+        forSeverity(Severity.ERROR).add(textProvider.getText(key, arguments));
+    }
+
+    public void add(Severity severity, String key) {
+        forSeverity(severity).add(textProvider.getText(key));
+    }
+
+    public void add(Severity severity, String key, String... arguments) {
+        forSeverity(severity).add(textProvider.getText(key, arguments));
+    }
+
+    public Set<Severity> getSeverities() {
+        Set<Severity> severities = EnumSet.noneOf(Severity.class);
+        for (Severity severity : Severity.values()) {
+            List<String> messages = severityMap.get(severity);
+            if (messages != null && !messages.isEmpty()) {
+                severities.add(severity);
+            }
+        }
+        return Collections.unmodifiableSet(severities);
+    }
+
+    public List<String> forSeverity(Severity severity) {
+        List<String> messages = severityMap.get(severity);
+        if (messages == null) {
+            messages = new ArrayList<String>();
+            severityMap.put(severity, messages);
+        }
+        return messages;
+    }
+
+    public List<String> getErrors() {
+        return forSeverity(Severity.ERROR);
+    }
+
+    public List<String> getWarnings() {
+        return forSeverity(Severity.WARN);
+    }
+
+    public List<String> getInformation() {
+        return forSeverity(Severity.INFO);
+    }
+
+    public boolean hasErrors() {
+        return !isEmpty(Severity.ERROR);
+    }
+
+    public boolean hasWarnings() {
+        return !isEmpty(Severity.WARN);
+    }
+
+    public boolean hasInformation() {
+        return !isEmpty(Severity.INFO);
+    }
+
+    public boolean isEmpty() {
+        for (Severity severity : Severity.values())
+            if (!isEmpty(severity))
+                return false;
+
+        return true;
+    }
+
+    public boolean isEmpty(Severity severity) {
+        List<String> messages = severityMap.get(severity);
+        if (messages != null && !messages.isEmpty()) {
+            return false;
+        }
+
+        for (Messages fieldMessages : fieldMap.values())
+            if (!fieldMessages.isEmpty(severity))
+                return false;
+
+        return true;
+    }
+}

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/RequestContextImpl.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/RequestContextImpl.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/RequestContextImpl.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/RequestContextImpl.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,172 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import org.apache.struts2.Messages;
+import static org.apache.struts2.StrutsStatics.*;
+import org.apache.struts2.dispatcher.RequestMap;
+import org.apache.struts2.spi.ActionContext;
+import org.apache.struts2.spi.RequestContext;
+import org.apache.struts2.spi.ValueStack;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+public class RequestContextImpl implements RequestContext {
+
+    com.opensymphony.xwork2.ActionContext xworkContext;
+    ActionContext actionContext;
+    Messages messages = new MessagesImpl();
+
+    public static final Callable<String> ILLEGAL_PROCEED = new Callable<String>() {
+        public String call() throws Exception {
+            throw new IllegalStateException();
+        }
+    };
+
+    public RequestContextImpl(com.opensymphony.xwork2.ActionContext xworkContext) {
+        this.xworkContext = xworkContext;
+    }
+
+    public ActionContext getActionContext() {
+        return actionContext;
+    }
+
+    public Object getAction() {
+        return getActionContext().getAction();
+    }
+
+    void setActionContext(ActionContext actionContext) {
+        this.actionContext = actionContext;
+    }
+
+    public Map<String, String[]> getParameterMap() {
+        return xworkContext.getParameters();
+    }
+
+    Map<String, Object> attributeMap;
+
+    public Map<String, Object> getAttributeMap() {
+        if (attributeMap == null) {
+            attributeMap = new RequestMap(getServletRequest());
+        }
+        return attributeMap;
+    }
+
+    public Map<String, Object> getSessionMap() {
+        return xworkContext.getSession();
+    }
+
+    public Map<String, Object> getApplicationMap() {
+        return xworkContext.getApplication();
+    }
+
+    public List<Cookie> findCookiesForName(String name) {
+        List<Cookie> cookies = new ArrayList<Cookie>();
+        for (Cookie cookie : getServletRequest().getCookies())
+            if (name.equals(cookie.getName()))
+                cookies.add(cookie);
+
+        return cookies;
+   }
+
+    public Locale getLocale() {
+        return xworkContext.getLocale();
+    }
+
+    public void setLocale(Locale locale) {
+        xworkContext.setLocale(locale);
+    }
+
+    public Messages getMessages() {
+        return messages;
+    }
+
+    public HttpServletRequest getServletRequest() {
+        return (HttpServletRequest) xworkContext.get(HTTP_REQUEST);
+    }
+
+    public HttpServletResponse getServletResponse() {
+        return (HttpServletResponse) xworkContext.get(HTTP_RESPONSE);
+    }
+
+    public ServletContext getServletContext() {
+        return (ServletContext) xworkContext.get(SERVLET_CONTEXT);
+    }
+
+    ValueStack valueStack;
+
+    public ValueStack getValueStack() {
+        if (valueStack == null) {
+            valueStack = new ValueStackAdapter(xworkContext.getValueStack());
+        }
+        return valueStack;
+    }
+
+    Callable<String> proceed = ILLEGAL_PROCEED;
+
+    public String proceed() throws Exception {
+        return proceed.call();
+    }
+
+    public void setProceed(Callable<String> proceed) {
+        this.proceed = proceed;
+    }
+
+    public Callable<String> getProceed() {
+        return proceed;
+    }
+
+    static ThreadLocal<RequestContextImpl[]> threadLocalRequestContext = new ThreadLocal<RequestContextImpl[]>() {
+        protected RequestContextImpl[] initialValue() {
+            return new RequestContextImpl[1];
+        }
+    };
+
+    /**
+     * Creates RequestContext if necessary. Always creates a new ActionContext and restores an existing ActionContext
+     * when finished.
+     */
+    public static String callInContext(ActionInvocation invocation, Callable<String> callable)
+            throws Exception {
+        RequestContextImpl[] reference = threadLocalRequestContext.get();
+
+        if (reference[0] == null) {
+            // Initial invocation.
+            reference[0] = new RequestContextImpl(invocation.getInvocationContext());
+            reference[0].setActionContext(new ActionContextImpl(invocation));
+            try {
+                return callable.call();
+            } finally {
+                reference[0] = null;
+            }
+        } else {
+            // Nested invocation.
+            RequestContextImpl requestContext = reference[0];
+            ActionContext previous = requestContext.getActionContext();
+            requestContext.setActionContext(new ActionContextImpl(invocation));
+            try {
+                return callable.call();
+            } finally {
+                requestContext.setActionContext(previous);
+            }
+        }
+    }
+
+    public static RequestContextImpl get() {
+        RequestContextImpl requestContext = threadLocalRequestContext.get()[0];
+
+        if (requestContext == null)
+            throw new IllegalStateException("RequestContext has not been created.");
+
+        return requestContext;
+    }
+}

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ResultAdapter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ResultAdapter.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ResultAdapter.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ResultAdapter.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,19 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import com.opensymphony.xwork2.Result;
+import com.opensymphony.xwork2.ActionInvocation;
+
+public class ResultAdapter implements Result {
+
+    final org.apache.struts2.spi.Result delegate;
+
+    public ResultAdapter(org.apache.struts2.spi.Result delegate) {
+        this.delegate = delegate;
+    }
+
+    public void execute(ActionInvocation invocation) throws Exception {
+        delegate.execute(RequestContextImpl.get());
+    }
+}

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxy.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxy.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxy.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxy.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,33 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import com.opensymphony.xwork2.DefaultActionProxy;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.config.Configuration;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+public class StrutsActionProxy extends DefaultActionProxy {
+
+    public StrutsActionProxy(Configuration cfg, String namespace, String actionName, Map extraContext,
+                             boolean executeResult, boolean cleanupContext) throws Exception {
+        super(cfg, namespace, actionName, extraContext, executeResult, cleanupContext);
+    }
+
+    public String execute() throws Exception {
+        ActionContext previous = ActionContext.getContext();
+        ActionContext.setContext(invocation.getInvocationContext());
+        try {
+            return RequestContextImpl.callInContext(invocation, new Callable<String>() {
+                public String call() throws Exception {
+                    return invocation.invoke();
+                }
+            });
+        } finally {
+            if (cleanupContext)
+                ActionContext.setContext(previous);
+        }
+    }
+}

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxyFactory.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxyFactory.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxyFactory.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsActionProxyFactory.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,22 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.DefaultActionProxyFactory;
+import com.opensymphony.xwork2.config.Configuration;
+
+import java.util.Map;
+
+public class StrutsActionProxyFactory extends DefaultActionProxyFactory {
+
+    public ActionProxy createActionProxy(Configuration config, String namespace, String actionName, Map extraContext)
+            throws Exception {
+        return new StrutsActionProxy(config, namespace, actionName, extraContext, true, true);
+    }
+
+    public ActionProxy createActionProxy(Configuration config, String namespace, String actionName, Map extraContext,
+            boolean executeResult, boolean cleanupContext) throws Exception {
+        return new StrutsActionProxy(config, namespace, actionName, extraContext, executeResult, cleanupContext);
+    }
+}

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsObjectFactory.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsObjectFactory.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsObjectFactory.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/StrutsObjectFactory.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,84 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.Result;
+import com.opensymphony.xwork2.util.OgnlUtil;
+import com.opensymphony.xwork2.config.entities.InterceptorConfig;
+import com.opensymphony.xwork2.config.entities.ResultConfig;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.interceptor.Interceptor;
+
+import java.util.Map;
+import java.util.HashMap;
+
+public class StrutsObjectFactory extends ObjectFactory {
+
+    public Interceptor buildInterceptor(InterceptorConfig interceptorConfig, Map refParams)
+            throws ConfigurationException {
+        String className = interceptorConfig.getClassName();
+
+        Map<String, String> params = new HashMap<String, String>();
+        Map typeParams = interceptorConfig.getParams();
+        if (typeParams != null && !typeParams.isEmpty())
+            params.putAll(typeParams);
+        if (refParams != null && !refParams.isEmpty())
+            params.putAll(refParams);
+        params.putAll(refParams);
+
+        try {
+            // interceptor instances are long-lived and used across user sessions, so don't try to pass in any extra
+            // context
+            Object o = buildBean(className, null);
+            OgnlUtil.setProperties(params, o);
+
+            if (o instanceof Interceptor) {
+                Interceptor interceptor = (Interceptor) o;
+                interceptor.init();
+                return interceptor;
+            }
+
+            if (o instanceof org.apache.struts2.spi.Interceptor)
+                return new InterceptorAdapter((org.apache.struts2.spi.Interceptor) o);
+
+            throw new ConfigurationException(
+                    "Class [" + className + "] does not implement Interceptor", interceptorConfig);
+        } catch (InstantiationException e) {
+            throw new ConfigurationException(
+                    "Unable to instantiate an instance of Interceptor class [" + className + "].",
+                    e, interceptorConfig);
+        } catch (IllegalAccessException e) {
+            throw new ConfigurationException(
+                    "IllegalAccessException while attempting to instantiate an instance of Interceptor class ["
+                            + className + "].",
+                    e, interceptorConfig);
+        } catch (Exception e) {
+            throw new ConfigurationException(
+                    "Caught Exception while registering Interceptor class " + className,
+                    e, interceptorConfig);
+        } catch (NoClassDefFoundError e) {
+            throw new ConfigurationException(
+                    "Could not load class " + className
+                            + ". Perhaps it exists but certain dependencies are not available?",
+                    e, interceptorConfig);
+        }
+    }
+
+    public Result buildResult(ResultConfig resultConfig, Map extraContext) throws Exception {
+        String resultClassName = resultConfig.getClassName();
+        if (resultClassName == null)
+            return null;
+
+        Object result = buildBean(resultClassName, extraContext);
+        OgnlUtil.setProperties(resultConfig.getParams(), result, extraContext);
+
+        if (result instanceof Result)
+            return (Result) result;
+
+        if (result instanceof org.apache.struts2.spi.Result)
+            return new ResultAdapter((org.apache.struts2.spi.Result) result);
+
+        throw new ConfigurationException(result.getClass().getName() + " does not implement Result.");
+    }
+}

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ValueStackAdapter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ValueStackAdapter.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ValueStackAdapter.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/impl/ValueStackAdapter.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,57 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import com.opensymphony.xwork2.util.OgnlValueStack;
+import org.apache.struts2.spi.ValueStack;
+
+import java.util.Iterator;
+
+public class ValueStackAdapter implements ValueStack {
+
+    final OgnlValueStack delegate;
+
+    public ValueStackAdapter(OgnlValueStack delegate) {
+        this.delegate = delegate;
+    }
+
+    public Object peek() {
+        return delegate.peek();
+    }
+
+    public Object pop() {
+        return delegate.pop();
+    }
+
+    public void push(Object o) {
+        delegate.push(o);
+    }
+
+    public ValueStack clone() {
+        return new ValueStackAdapter(new OgnlValueStack(delegate));
+    }
+
+    public Object get(String expr) {
+        return delegate.findValue(expr);
+    }
+
+    public <T> T get(String expr, Class<T> requiredType) {
+        return (T) delegate.findValue(expr, requiredType);
+    }
+
+    public String getString(String expr) {
+        return delegate.findString(expr);
+    }
+
+    public void set(String expr, Object o) {
+        delegate.set(expr, o);
+    }
+
+    public int size() {
+        return delegate.size();
+    }
+
+    public Iterator<Object> iterator() {
+        return delegate.getRoot().iterator();
+    }
+}
\ No newline at end of file

Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/MessagesTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/MessagesTest.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/MessagesTest.java (added)
+++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/MessagesTest.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,30 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import junit.framework.TestCase;
+import org.apache.struts2.Messages;
+
+public class MessagesTest extends TestCase {
+
+    public void testForField() {
+        Messages messages = new MessagesImpl();
+        Messages fieldMessages = messages.forField("foo");
+        fieldMessages.addError("foo");
+        assertFalse(fieldMessages.getErrors().isEmpty());
+        assertTrue(messages.hasErrors());
+    }
+
+    public void testHasMessagesForSeverity() {
+        for (Messages.Severity severity : Messages.Severity.values()) {
+            Messages messages = new MessagesImpl();
+            messages.add(severity, "foo");
+
+            assertFalse(messages.isEmpty(severity));
+
+            for (Messages.Severity other : Messages.Severity.values())
+                if (other != severity)
+                    assertTrue(messages.isEmpty(other));
+        }
+    }
+}

Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/RequestContextTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/RequestContextTest.java?rev=427807&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/RequestContextTest.java (added)
+++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/impl/RequestContextTest.java Tue Aug  1 17:07:17 2006
@@ -0,0 +1,67 @@
+// Copyright 2006 Google Inc. All Rights Reserved.
+
+package org.apache.struts2.impl;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ActionContext;
+import junit.framework.TestCase;
+import static org.easymock.EasyMock.*;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+import java.util.List;
+import java.util.HashMap;
+import java.util.concurrent.Callable;
+
+public class RequestContextTest extends TestCase {
+
+    public void testFindCookiesForName() {
+        final HttpServletRequest servletRequest = createMock(HttpServletRequest.class);
+        Cookie one = new Cookie("foo", "one");
+        Cookie two = new Cookie("foo", "two");
+        Cookie three = new Cookie("bar", "three");
+        Cookie[] cookies = { one, two, three };
+        expect(servletRequest.getCookies()).andReturn(cookies);
+
+        replay(servletRequest);
+
+        RequestContextImpl requestContext = new RequestContextImpl(null) {
+            public HttpServletRequest getServletRequest() {
+                return servletRequest;
+            }
+        };
+
+        List<Cookie> fooCookies = Arrays.asList(one, two);
+        assertEquals(fooCookies, requestContext.findCookiesForName("foo"));
+    }
+
+    public void testInitialCallInContext() throws Exception {
+        final ActionInvocation invocation = createMock(ActionInvocation.class);
+        final ActionContext actionContext = new ActionContext(new HashMap());
+        expect(invocation.getInvocationContext()).andReturn(actionContext);
+
+        final boolean[] called = new boolean[1];
+        Callable<String> callable = new Callable<String>() {
+            public String call() throws Exception {
+                RequestContextImpl requestContext = RequestContextImpl.get();
+                assertSame(actionContext, requestContext.xworkContext);
+                assertSame(invocation,
+                        ((ActionContextImpl) requestContext.getActionContext()).invocation);
+                called[0] = true;
+                return "foo";
+            }
+        };
+
+        replay(invocation);
+
+        assertEquals("foo", RequestContextImpl.callInContext(invocation, callable));
+        assertTrue(called[0]);
+        assertNull(RequestContextImpl.threadLocalRequestContext.get()[0]);
+    }
+
+    public void testNestedCallInContext() throws Exception {
+        // TODO: After we implement ActionContext.getNext(), getPrevious().
+    }
+}
+