You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by ge...@apache.org on 2005/02/07 02:42:36 UTC

svn commit: r151657 - in struts/core/trunk/src: share/org/apache/struts/chain/commands/generic/ share/org/apache/struts/chain/contexts/ test/org/apache/struts/chain/commands/generic/

Author: germuska
Date: Sun Feb  6 17:42:35 2005
New Revision: 151657

URL: http://svn.apache.org/viewcvs?view=rev&rev=151657
Log:
Commit classes involved in revisions to chain, slightly in advance of checking in changes to the chain commands themselves.

Added:
    struts/core/trunk/src/share/org/apache/struts/chain/commands/generic/
    struts/core/trunk/src/share/org/apache/struts/chain/commands/generic/WrappingLookupCommand.java
    struts/core/trunk/src/share/org/apache/struts/chain/contexts/
    struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContext.java
    struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContextBase.java
    struts/core/trunk/src/share/org/apache/struts/chain/contexts/ContextWrapper.java
    struts/core/trunk/src/share/org/apache/struts/chain/contexts/ServletActionContext.java
    struts/core/trunk/src/share/org/apache/struts/chain/contexts/WebActionContext.java
    struts/core/trunk/src/test/org/apache/struts/chain/commands/generic/
    struts/core/trunk/src/test/org/apache/struts/chain/commands/generic/TestWrappingLookupCommand.java

Added: struts/core/trunk/src/share/org/apache/struts/chain/commands/generic/WrappingLookupCommand.java
URL: http://svn.apache.org/viewcvs/struts/core/trunk/src/share/org/apache/struts/chain/commands/generic/WrappingLookupCommand.java?view=auto&rev=151657
==============================================================================
--- struts/core/trunk/src/share/org/apache/struts/chain/commands/generic/WrappingLookupCommand.java (added)
+++ struts/core/trunk/src/share/org/apache/struts/chain/commands/generic/WrappingLookupCommand.java Sun Feb  6 17:42:35 2005
@@ -0,0 +1,204 @@
+/*
+ * $Id$ 
+ * 
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.chain.commands.generic;
+
+import org.apache.commons.beanutils.ConstructorUtils;
+import org.apache.commons.chain.Catalog;
+import org.apache.commons.chain.CatalogFactory;
+import org.apache.commons.chain.Command;
+import org.apache.commons.chain.Context;
+import org.apache.commons.chain.Filter;
+import org.apache.struts.chain.commands.util.ClassUtils;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.Log;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Variant on chain LookupCommand which can optionally
+ * wrap the context it passes to the looked up command
+ * in an alternative class.
+ * 
+ */
+public class WrappingLookupCommand implements Filter {
+
+    public WrappingLookupCommand()
+    {
+        catalogName = null;
+        name = null;
+        nameKey = null;
+        optional = false;
+    }
+
+    // ------------------------------------------------------ Instance Variables
+    private String catalogName = null;
+    private String name = null;
+    private String nameKey = null;
+    private String wrapperClassName = null;
+    private boolean optional = false;
+
+    private static final Log log = LogFactory.getLog(WrappingLookupCommand.class);
+
+
+    public String getCatalogName()
+    {
+        return catalogName;
+    }
+
+    public void setCatalogName(String catalogName)
+    {
+        this.catalogName = catalogName;
+    }
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    public String getNameKey()
+    {
+        return nameKey;
+    }
+
+    public void setNameKey(String nameKey)
+    {
+        this.nameKey = nameKey;
+    }
+
+    public boolean isOptional()
+    {
+        return optional;
+    }
+
+    public void setOptional(boolean optional)
+    {
+        this.optional = optional;
+    }
+
+    public String getWrapperClassName() {
+        return wrapperClassName;
+    }
+
+    public void setWrapperClassName(String wrapperClassName) {
+        this.wrapperClassName = wrapperClassName;
+    }
+
+    public boolean execute(Context context)
+        throws Exception
+    {
+        log.trace("execute ["+this+"]");
+        Command command = getCommand(context);
+        if(command != null)
+            return command.execute(getContext(context));
+        else
+            return false;
+    }
+
+    public boolean postprocess(Context context, Exception exception)
+    {
+        Command command = getCommand(context);
+        if(command != null && (command instanceof Filter)) {
+            try {
+                return ((Filter)command).postprocess(getContext(context), exception);
+            }
+            catch (NoSuchMethodException ex) {
+                log.error("Error wrapping context in postprocess", ex);
+            }catch (IllegalAccessException ex) {
+                log.error("Error wrapping context in postprocess", ex);
+            }catch (InvocationTargetException ex) {
+                log.error("Error wrapping context in postprocess", ex);
+            }catch (InstantiationException ex) {
+                log.error("Error wrapping context in postprocess", ex);
+            }catch (ClassNotFoundException ex) {
+                log.error("Error wrapping context in postprocess", ex);
+            }
+        }
+        return false;
+    }
+
+    protected Command getCommand(Context context)
+    {
+        CatalogFactory catalogFactory = CatalogFactory.getInstance();
+        String catalogName = getCatalogName();
+        Catalog catalog = null;
+        if(catalogName == null) {
+            catalog = catalogFactory.getCatalog();
+            catalogName = "{default}"; // for debugging purposes
+        } else {
+            catalog = catalogFactory.getCatalog(catalogName);
+        }
+        if(catalog == null) {
+            throw new IllegalArgumentException("Cannot find catalog '" + catalogName + "'");
+        }
+
+        Command command = null;
+        String name = getName();
+
+        if(name == null) {
+            name = (String)context.get(getNameKey());
+        }
+
+        if(name != null)
+        {
+            log.debug("Lookup command " + name + " in catalog " + catalogName);
+            command = catalog.getCommand(name);
+            log.debug("Found command " + command + "; optional: " + isOptional());
+            if(command == null && !isOptional())
+            {
+                throw new IllegalArgumentException("Cannot find command '" + name + "' in catalog '" + catalogName + "'");
+            } else 
+            {
+                return command;
+            }
+        } else
+        {
+            throw new IllegalArgumentException("No command name");
+        }
+    }
+
+    /**
+     * If the <code>wrapperClassName</code> property is not null, return a <code>Context</code>
+     * of the type specified by <code>wrapperClassName</code>, instantiated using a single-arg
+     * constructor which takes the <code>context</code> passed as an argument to this method.
+     * @param context
+     * @return
+     * @throws Exception if the wrapperClass cannot be found, or if there are any errors instantiating
+     * the wrapping context.
+     */
+    protected Context getContext(Context context) 
+            throws ClassNotFoundException, 
+                   InstantiationException,
+                   InvocationTargetException,
+                   IllegalAccessException,
+                   NoSuchMethodException
+    {
+        if (wrapperClassName == null) {
+            log.debug("No defined wrapper class; returning original context.");
+            return context;
+        }
+        log.debug("Looking for wrapper class: " + wrapperClassName);
+        Class wrapperClass = ClassUtils.getApplicationClass(wrapperClassName);
+        log.debug("Instantiating wrapper class");
+        return (Context) ConstructorUtils.invokeConstructor(wrapperClass, new Object[] { context });
+    }
+
+}
\ No newline at end of file

Added: struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContext.java
URL: http://svn.apache.org/viewcvs/struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContext.java?view=auto&rev=151657
==============================================================================
--- struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContext.java (added)
+++ struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContext.java Sun Feb  6 17:42:35 2005
@@ -0,0 +1,462 @@
+/*
+ * $Id$ 
+ * 
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.chain.contexts;
+
+import java.util.Locale;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.chain.Context;
+import org.apache.struts.action.ActionMessages;
+import org.apache.struts.util.MessageResources;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.config.ActionConfig;
+import org.apache.struts.config.ForwardConfig;
+import org.apache.struts.config.ModuleConfig;
+import org.apache.struts.action.Action;
+
+
+/**
+ * <p>An ActionContext represents a view of a commons-chain 
+ * <code>Context</code> which encapsulates access to request 
+ * and session-scoped resources and services</p>
+ */
+public interface ActionContext extends Context {
+
+    public static final String APPLICATION_SCOPE = "application";
+    
+    public static final String SESSION_SCOPE = "session";
+    
+    public static final String REQUEST_SCOPE = "request";
+
+    // -------------------------------
+    // General Application Support
+    // -------------------------------
+    /**
+     * <p>Return a <code>Map</code> of Application scoped values.</p>  
+     * 
+     * <p>This is implemented in analogy with the Application scope in 
+     * the Servlet API, but it seems reasonable to expect that any
+     * Struts implementation will have an equivalent concept.</p>
+     * 
+     * <p>The ultimate meaning of "application scope" is an implementation detail 
+     * left unspecified by Struts.</p>
+     * @return
+     */
+    Map getApplicationScope();
+    
+    /**
+     * <p>Return a <code>Map</code> of Session scoped values.  A session
+     * is understood as a sequence of requests made by the same user.</p>  
+     * 
+     * <p>This is implemented in analogy with the Session scope in 
+     * the Servlet API, but it seems reasonable to expect that any
+     * Struts implementation will have an equivalent concept.</p>
+     * 
+     * <p>The ultimate meaning of "session scope" is an implementation detail 
+     * left unspecified by Struts.</p>
+     * @return
+     */
+    Map getSessionScope();
+    
+    /**
+     * <p>Return a <code>Map</code> of request scoped values.  A 
+     * request is understood as the fundamental motivation for any 
+     * particular instance of an <code>ActionContext</code>.</p>
+     * 
+     * <p>This is implemented in analogy with the Request Context in 
+     * the Servlet API, but it seems reasonable to expect that any
+     * Struts implementation will have an equivalent concept.</p>
+     * 
+     * <p>The ultimate meaning of "request scope" is an implementation detail 
+     * left unspecified by Struts.</p>
+     * @return
+     */
+    Map getRequestScope();
+
+    /**
+     * <p>Return a <code>Map</code> of parameters submitted by the user
+     * as part of this request.</p>
+     * 
+     * <p>This is implemented in analogy with the Request parameters of 
+     * the Servlet API, but it seems reasonable to expect that any
+     * Struts implementation will have an equivalent concept.</p>
+     * 
+     * @return
+     */
+    Map getParameterMap();
+    
+    // -------------------------------
+    // General Struts properties
+    // -------------------------------
+
+    /**
+     * Set the action which has been identified to be executed as part
+     * of processing this request.
+     * @param action
+     */
+    void setAction(Action action);
+
+    /**
+     * Get the action which has been identified to be executed as part
+     * of processing this request.
+     * 
+     * @return
+     */
+    Action getAction();
+
+    /**
+     * Set the ActionForm instance which will carry any data submitted
+     * as part of this request.
+
+     * @param form
+     */
+    void setActionForm(ActionForm form);
+
+    /**
+     * Get the ActionForm instance which will carry any data submitted as 
+     * part of this request.
+     * 
+     * @return
+     */
+    ActionForm getActionForm();
+
+    /**
+     * Set the ActionConfig class contains the details 
+     * for processing this request.
+     * @param config
+     */
+    void setActionConfig(ActionConfig config);
+
+    /**
+     * Get the ActionConfig which contains the details for processing this request.
+     * @return
+     */
+    ActionConfig getActionConfig();
+
+    /**
+     * Set the ForwardConfig which should be used as the basis of the view segment 
+     * of the overall processing.  This is the primary method of "communication" with
+     * the "view" sub-chain.
+     * 
+     * @param forward
+     */
+    void setForwardConfig(ForwardConfig forward);
+
+    /**
+     * Get the ForwardConfig which has been identified as the basis for view-processing.
+     * 
+     * @return
+     */
+    ForwardConfig getForwardConfig();
+
+    /**
+     * Set the include path which should be processed as part of processing this request.
+     * 
+     * @param forward
+     */
+    void setInclude(String include);
+
+    /**
+     * Get the include path which should be processed as part of processing this request.
+     * 
+     * @return
+     */
+    String getInclude();
+
+    /**
+     * Set the ModuleConfig which is operative for the current request.
+     * 
+     * @param config
+     */
+    void setModuleConfig(ModuleConfig config);
+
+    /**
+     * Get the ModuleConfig which is operative for the current request.
+     * @return 
+     */
+    ModuleConfig getModuleConfig();
+
+    /**
+     * Is the ActionForm for this context valid?  This <em>does not</em> actually perform
+     * form validation.  It is simply a holder property where processes which perform validation
+     * can store the results of the validation for other processes' benefit.
+     * 
+     * @return <code>Boolean.TRUE</code> if the form passed validation; <code>Boolean.FALSE</code>
+     * if the form failed validation; null if the form has not yet been validated.
+     */
+    Boolean getFormValid();
+
+    /**
+     * Store the result of the validation of the Context's ActionForm.
+     * @param valid
+     */
+    void setFormValid(Boolean valid);
+
+    // -------------------------------
+    // ActionMessage Processing
+    // -------------------------------
+
+    /**
+     * Adds the specified messages keys into the appropriate request
+     * attribute for use by the &lt;html:messages&gt; tag (if
+     * messages="true" is set), if any messages are required.
+     * Initialize the attribute if it has not already been.
+     * Otherwise, ensure that the request attribute is not set.
+     *
+     * @param messages  Messages object
+     */
+    void addMessages(ActionMessages messages);
+
+    /**
+     * Adds the specified errors keys into the appropriate request
+     * attribute for use by the for use by the &lt;html:errors&gt; tag,
+     * if any messages are required.
+     * Initialize the attribute if it has not already been.
+     * Otherwise, ensure that the request attribute is not set.
+     *
+     * @param errors  Errors object
+     */
+    void addErrors(ActionMessages errors);
+
+    /**
+     * Retrieves any existing errors placed in the request by previous actions.  This method could be called instead
+     * of creating a <code>new ActionMessages()<code> at the beginning of an <code>Action<code>
+     * This will prevent saveErrors() from wiping out any existing Errors
+     *
+     * @return the Errors that already exist in the request, or a new ActionMessages object if empty.
+     * @param request The servlet request we are processing
+     */
+    ActionMessages getErrors();
+
+    /**
+     * Retrieves any existing messages placed in the request by previous actions.  This method could be called instead
+     * of creating a <code>new ActionMessages()<code> at the beginning of an <code>Action<code>
+     * This will prevent saveMessages() from wiping out any existing Messages
+     *
+     * @return the Messages that already exist in the request, or a new ActionMessages object if empty.
+     * @param request The servlet request we are processing
+     */
+    ActionMessages getMessages();
+
+    /**
+     * <p>Save the specified error messages keys into the appropriate request
+     * attribute for use by the &lt;html:errors&gt; tag, if any messages
+     * are required. Otherwise, ensure that the request attribute is not
+     * created.</p>
+     *
+     * @param request The servlet request we are processing
+     * @param errors Error messages object
+     */
+    void saveErrors(ActionMessages errors);
+
+
+    /**
+     * <p>Save the specified messages keys into the appropriate request
+     * attribute for use by the &lt;html:messages&gt; tag (if
+     * messages="true" is set), if any messages are required. Otherwise,
+     * ensure that the request attribute is not created.</p>
+     *
+     * @param messages The messages to save. <code>null</code> or empty
+     * messages removes any existing ActionMessages in the request.
+     *
+     */
+    void saveMessages(ActionMessages messages);
+
+
+    /**
+     * <p>Save the specified messages keys into the appropriate scope 
+     * for use by the &lt;html:messages&gt; tag (if
+     * messages="true" is set), if any messages are required. Otherwise,
+     * ensure that the session attribute is not created.</p>
+     *
+     * @param messages The messages to save. <code>null</code> or empty
+     * messages removes any existing ActionMessages in the session.
+     *
+     */
+    void saveMessages(String scope, ActionMessages messages);
+
+    // -------------------------------
+    // Token Processing
+    // -------------------------------
+
+    /**
+     * <p>Generate a new transaction token, to be used for enforcing a single
+     * request for a particular transaction.</p>
+     *
+     */
+    String generateToken();
+
+    /**
+     * <p>Return <code>true</code> if there is a transaction token stored in
+     * the user's current session, and the value submitted as a request
+     * parameter with this action matches it. Returns <code>false</code>
+     * under any of the following circumstances:</p>
+     * <ul>
+     * <li>No session associated with this request</li>
+     * <li>No transaction token saved in the session</li>
+     * <li>No transaction token included as a request parameter</li>
+     * <li>The included transaction token value does not match the
+     *     transaction token in the user's session</li>
+     * </ul>
+     *
+     * @param request The servlet request we are processing
+     */
+    boolean isTokenValid();
+
+
+    /**
+     * <p>Return <code>true</code> if there is a transaction token stored in
+     * the user's current session, and the value submitted as a request
+     * parameter with this action matches it. Returns <code>false</code>.</p>
+     * <ul>
+     * <li>No session associated with this request</li>
+     * <li>No transaction token saved in the session</li>
+     * <li>No transaction token included as a request parameter</li>
+     * <li>The included transaction token value does not match the
+     *     transaction token in the user's session</li>
+     * </ul>
+     *
+     * @param request The servlet request we are processing
+     * @param reset Should we reset the token after checking it?
+     */
+    boolean isTokenValid(boolean reset);
+
+
+    /**
+     * <p>Reset the saved transaction token in the user's session. This
+     * indicates that transactional token checking will not be needed
+     * on the next request that is submitted.</p>
+     *
+     * @param request The servlet request we are processing
+     */
+    void resetToken();
+
+
+
+    /**
+     * <p>Save a new transaction token in the user's current session, creating
+     * a new session if necessary.</p>
+     *
+     * @param request The servlet request we are processing
+     */
+    void saveToken();
+
+
+
+
+
+    // -------------------------------
+    // Cancel Processing
+    // -------------------------------
+
+    /**
+     * <p>Returns <code>Boolean.TRUE</code> if the current form's cancel button was
+     * pressed. Rather than evaluating any system state, 
+     * this simply reflects the value of the <code>cancelled</code> property,
+     * assuming it was set elsewhere by some other process.</p>
+     *
+     * @see org.apache.struts.taglib.html.CancelTag
+     */
+    Boolean getCancelled();
+
+    /**
+     * <p>Indicate that the current form was detected to be cancelled.</p>
+     * @param cancelled
+     */
+    void setCancelled(Boolean cancelled);
+
+
+    // -------------------------------
+    // MessageResources Processing
+    // -------------------------------
+
+    /**
+     * <p>Return the default message resources for the current module.</p>
+     *
+     */
+    MessageResources getMessageResources();
+
+    /**
+     * <p>Set the default message resources for the current module.</p>
+     *
+     * @return the default message resources for the current module.
+     */
+    void setMessageResources(MessageResources resources);
+
+
+    /**
+     * <p>Return the specified message resources for the current module.</p>
+     *
+     * @param request The servlet request we are processing
+     * @param key The key specified in the
+     *  <code>&lt;message-resources&gt;</code> element for the
+     *  requested bundle
+     *
+     */
+    MessageResources getMessageResources(String key);
+
+    // -------------------------------
+    // Locale Processing
+    // -------------------------------
+
+    /**
+     * <p>Return the user's currently selected Locale.</p>
+     *
+     */
+    Locale getLocale();
+
+
+
+    /**
+     * <p>Set the user's currently selected <code>Locale</code>.</p>
+     *
+     * @param locale The user's selected Locale to be set, or null
+     *  to select the server's default Locale
+     */
+    void setLocale(Locale locale);
+
+    // -------------------------------
+    // DataSource Processing
+    // -------------------------------
+
+
+
+    /**
+     * <p>Return the default data source for the current module.</p>
+     *
+     * @param request The servlet request we are processing
+     *
+     */
+    DataSource getDataSource();
+
+
+
+    /**
+     * <p>Return the specified data source for the current module.</p>
+     *
+     * @param request The servlet request we are processing
+     * @param key The key specified in the
+     *  <code>&lt;message-resources&gt;</code> element for the
+     *  requested bundle
+     *
+     */
+    DataSource getDataSource(String key);
+
+}
\ No newline at end of file

Added: struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContextBase.java
URL: http://svn.apache.org/viewcvs/struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContextBase.java?view=auto&rev=151657
==============================================================================
--- struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContextBase.java (added)
+++ struts/core/trunk/src/share/org/apache/struts/chain/contexts/ActionContextBase.java Sun Feb  6 17:42:35 2005
@@ -0,0 +1,340 @@
+/*
+ * $Id$ 
+ * 
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.chain.contexts;
+
+import java.util.Locale;
+import java.util.Map;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.chain.Context;
+import org.apache.struts.action.ActionMessages;
+import org.apache.struts.util.MessageResources;
+import org.apache.commons.chain.impl.ContextBase;
+import org.apache.struts.util.TokenProcessor;
+import org.apache.struts.chain.Constants;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.config.ActionConfig;
+import org.apache.struts.config.ForwardConfig;
+import org.apache.struts.config.ModuleConfig;
+import org.apache.struts.action.Action;
+
+
+
+/**
+ * <p>Title: struts</p>
+ * <p>Description: The core of the Struts framework is a flexible control layer based on standard technologies like Java Servlets, JavaBeans, ResourceBundles, and Extensible Markup Language (XML), as well as various Jakarta Commons packages. Struts encourages application architectures based on the Model 2 approach, a variation of the classic Model-View-Controller (MVC) design paradigm. Struts provides its own Controller component and integrates with other technologies to provide the Model and the View. For the Model, Struts can interact with any standard data access technology, including Enterprise Java Beans, JDBC, and Object Relational Bridge. For the View, Struts works well with JavaServer Pages, including JSTL and JSF, as well as Velocity Templates, XSLT, and other presentation systems. The Struts framework provides the invisible underpinnings every professional web application needs to survive. Struts helps you create an extensible development environment for your application, based on published standards and proven design patterns.</p>
+ * <p>Copyright: Copyright (c) 2000-2004 The Apache Software Foundation - All Rights Reserved.</p>
+ * <p>Company: The Apache Software Foundation</p>
+ * @author germuska
+ * @version 1.2.5
+ */
+
+public abstract class ActionContextBase extends ContextWrapper implements ActionContext {
+
+
+    public static final String ACTION_KEY = Constants.ACTION_KEY;
+
+    public static final String ACTION_CONFIG_KEY = Constants.ACTION_CONFIG_KEY;
+
+    public static final String ACTION_FORM_KEY = Constants.ACTION_FORM_KEY;
+
+    public static final String FORWARD_CONFIG_KEY = Constants.FORWARD_CONFIG_KEY;
+
+    public static final String MODULE_CONFIG_KEY = Constants.MODULE_CONFIG_KEY;
+
+    public static final String DEFAULT_DATA_SOURCE_KEY = "dataSource";
+
+    public static final String ERROR_ACTION_MESSAGES_KEY = "errors";
+
+    public static final String MESSAGE_ACTION_MESSAGES_KEY = "messages";
+
+    public static final String MESSAGE_RESOURCES_KEY = Constants.MESSAGE_RESOURCES_KEY;
+
+    public static final String INCLUDE_KEY = Constants.INCLUDE_KEY;
+
+    public static final String LOCALE_KEY = Constants.LOCALE_KEY;
+
+    public static final String CANCEL_KEY = Constants.CANCEL_KEY;
+
+    public static final String VALID_KEY = Constants.VALID_KEY;
+
+    public static final String TRANSACTION_TOKEN_KEY = "TRANSACTION_TOKEN_KEY";
+
+    public static final String TOKEN_KEY = "TOKEN_KEY";
+
+    TokenProcessor token = null;
+
+    public ActionContextBase(Context context) {
+        super(context);
+        token = TokenProcessor.getInstance();
+    }
+
+    public ActionContextBase() {
+        this(new ContextBase());
+    }
+
+    // -------------------------------
+    // General Application Support
+    // -------------------------------
+
+    public abstract Map getApplicationScope(); 
+
+    public abstract Map getRequestScope();
+
+    public abstract Map getSessionScope();
+   
+    
+    // -------------------------------
+    // General Struts properties
+    // -------------------------------
+    public void setAction(Action action) {
+        this.put(ACTION_KEY, action);
+    }
+
+    public Action getAction() {
+        return (Action) this.get(ACTION_KEY);
+    }
+
+    public void setActionForm(ActionForm form) {
+        this.put(ACTION_FORM_KEY, form);
+    }
+
+    public ActionForm getActionForm() {
+        return (ActionForm) this.get(ACTION_FORM_KEY);
+    }
+
+    public void setActionConfig(ActionConfig config) {
+        this.put(ACTION_CONFIG_KEY, config);
+    }
+
+    public ActionConfig getActionConfig() {
+        return (ActionConfig) this.get(ACTION_CONFIG_KEY);
+    }
+
+    public  void setForwardConfig(ForwardConfig forward) {
+        this.put(FORWARD_CONFIG_KEY, forward);
+    }
+
+    public ForwardConfig getForwardConfig() {
+        return (ForwardConfig) this.get(FORWARD_CONFIG_KEY);
+    }
+
+    public void setInclude(String include) {
+        this.put(INCLUDE_KEY, include);
+    }
+
+    public String getInclude() {
+        return (String) this.get(INCLUDE_KEY);
+    }
+
+    public Boolean getFormValid() {
+        return (Boolean) this.get(VALID_KEY);
+    }
+
+    public void setFormValid(Boolean valid) {
+        this.put(VALID_KEY, valid);
+    }
+
+    public ModuleConfig getModuleConfig() {
+        return (ModuleConfig) this.get(MODULE_CONFIG_KEY);
+    }
+
+    public void setModuleConfig(ModuleConfig config) {
+        this.put(MODULE_CONFIG_KEY, config);
+    }
+
+    // -------------------------------
+    // ActionMessage Processing
+    // -------------------------------
+
+    public void addMessages(ActionMessages messages) {
+        this.addActionMessages(MESSAGE_ACTION_MESSAGES_KEY, messages);
+    }
+
+    public void addErrors(ActionMessages errors) {
+        this.addActionMessages(ERROR_ACTION_MESSAGES_KEY, errors);
+    }
+
+    public ActionMessages getErrors() {
+        return (ActionMessages) this.get(ERROR_ACTION_MESSAGES_KEY);
+    }
+
+    public ActionMessages getMessages() {
+        return (ActionMessages) this.get(MESSAGE_ACTION_MESSAGES_KEY);
+    }
+
+    public void saveErrors(ActionMessages errors) {
+        this.saveActionMessages(ERROR_ACTION_MESSAGES_KEY, errors);
+    }
+
+    public void saveMessages(ActionMessages messages) {
+        this.saveActionMessages(MESSAGE_ACTION_MESSAGES_KEY, messages);
+    }
+
+    // do we want to add this to the public API?
+    public void addActionMessages(String key, ActionMessages msgs) {
+
+        if (msgs == null){
+            //	bad programmer! *slap*
+            return;
+        }
+
+        // get any existing messages from the request, or make a new one
+        ActionMessages requestMessages = (ActionMessages) this.get(key);
+        if (requestMessages == null){
+            requestMessages = new ActionMessages();
+        }
+        // add incoming messages
+        requestMessages.add(msgs);
+
+        // if still empty, just wipe it out from the request
+        this.remove(key);
+
+        // Save the messages
+        this.saveActionMessages(key, requestMessages);
+    }
+
+    // do we want to add this to the public API?
+    public void saveActionMessages(String key, ActionMessages msgs) {
+        if ((msgs == null) || msgs.isEmpty()) {
+            this.remove(key);
+            return;
+        }
+        this.put(key, msgs);
+    }
+
+
+    /**
+     * ActionContextBase only has one scope, so this method delegates
+     * to saveMessages(messages).
+     * @param scope
+     * @param messages
+     */
+    public void saveMessages(String scope, ActionMessages messages) {
+        this.saveMessages(messages);
+    }
+
+
+    // -------------------------------
+    // Token Processing
+    // -------------------------------
+
+    /** @todo Is there a problem trying to map this method from Action 
+     * to ActionContext when we aren't necessarily sure how token 
+     * processing maps into a context with an ill-defined "session"?
+     * There's no getToken() method, but maybe there should be. */
+    public void saveToken() {
+        String token = this.generateToken();
+        this.put(TRANSACTION_TOKEN_KEY, token);
+    }
+
+    public String generateToken() {
+        return token.generateToken(getTokenGeneratorId());
+
+    }
+
+    protected String getTokenGeneratorId() {
+        /** @todo The original implementation was based on the HttpSession identifier; 
+         what would be a way to do that without depending on the Servlet API?
+         */
+        return "";
+
+    }
+
+    public boolean isTokenValid() {
+        return this.isTokenValid(false);
+    }
+
+    public boolean isTokenValid(boolean reset) {
+
+        // Retrieve the transaction token from this session, and
+        // reset it if requested
+        String saved = (String) this.get(TRANSACTION_TOKEN_KEY);
+        if (saved == null) {
+            return false;
+        }
+
+        if (reset) {
+            this.resetToken();
+        }
+
+        // Retrieve the transaction token included in this request
+        String token = (String) this.get(TOKEN_KEY);
+        if (token == null) {
+            return false;
+        }
+
+        return saved.equals(token);
+    }
+
+    public void resetToken() {
+        this.remove(TRANSACTION_TOKEN_KEY);
+    }
+
+    // -------------------------------
+    // Cancel Processing
+    // -------------------------------
+    public Boolean getCancelled() {
+        return (Boolean) this.get(CANCEL_KEY);
+    }
+
+    public void setCancelled(Boolean cancelled) {
+        this.put(CANCEL_KEY, cancelled);
+    }
+
+    // -------------------------------
+    // MessageResources Processing
+    // -------------------------------
+    public void setMessageResources(MessageResources messageResources) {
+        this.put(MESSAGE_RESOURCES_KEY, messageResources);
+    }
+
+    public MessageResources getMessageResources() {
+        return (MessageResources) this.get(MESSAGE_RESOURCES_KEY);
+    }
+
+    public MessageResources getMessageResources(String key) {
+        return (MessageResources) this.get(key);
+    }
+
+    // -------------------------------
+    // Locale Processing
+    // -------------------------------
+    public void setLocale(Locale locale) {
+        this.put(LOCALE_KEY, locale);
+    }
+
+
+    public Locale getLocale() {
+        return (Locale) this.get(LOCALE_KEY);
+    }
+
+    // -------------------------------
+    // DataSource Processing
+    // -------------------------------
+
+    public DataSource getDataSource() {
+        return (DataSource) this.get(DEFAULT_DATA_SOURCE_KEY);
+    }
+
+    public DataSource getDataSource(String key) {
+        return (DataSource) this.get(key);
+    }
+
+}
\ No newline at end of file

Added: struts/core/trunk/src/share/org/apache/struts/chain/contexts/ContextWrapper.java
URL: http://svn.apache.org/viewcvs/struts/core/trunk/src/share/org/apache/struts/chain/contexts/ContextWrapper.java?view=auto&rev=151657
==============================================================================
--- struts/core/trunk/src/share/org/apache/struts/chain/contexts/ContextWrapper.java (added)
+++ struts/core/trunk/src/share/org/apache/struts/chain/contexts/ContextWrapper.java Sun Feb  6 17:42:35 2005
@@ -0,0 +1,90 @@
+/*
+ * $Id$ 
+ * 
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.chain.contexts;
+
+import org.apache.commons.chain.Context;
+import java.util.Set;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * <code>ContextWrapper</code> is meant as a base class for any Context Implementation which
+ * is primarily intended for use in a subchain.  Classes which extend <code>ContextWrapper</code>
+ * may implement typesafe property methods which also leave their 
+ */
+public class ContextWrapper implements Context {
+
+    public ContextWrapper(Context context) {
+        this.base = context;
+    }
+
+    private Context base;
+
+    protected Context getBaseContext() {
+        return this.base;
+    }
+
+    public Set entrySet() {
+        return this.base.entrySet();
+    }
+
+    public Set keySet() {
+        return this.base.keySet();
+    }
+
+    public Collection values() {
+        return this.base.values();
+    }
+
+    public void clear() {
+        this.base.clear();
+    }
+
+    public void putAll(Map map) {
+        this.base.putAll(map);
+    }
+
+    public Object remove(Object key) {
+        return this.base.remove(key);
+    }
+
+    public Object put(Object key, Object value) {
+        return this.base.put(key, value);
+    }
+
+    public Object get(Object key) {
+        return this.base.get(key);
+    }
+
+    public boolean containsValue(Object o) {
+        return this.base.containsValue(o);
+    }
+
+    public boolean containsKey(Object o) {
+        return this.base.containsKey(o);
+    }
+
+    public boolean isEmpty() {
+        return this.base.isEmpty();
+    }
+
+    public int size() {
+        return this.base.size();
+    }
+
+}
\ No newline at end of file

Added: struts/core/trunk/src/share/org/apache/struts/chain/contexts/ServletActionContext.java
URL: http://svn.apache.org/viewcvs/struts/core/trunk/src/share/org/apache/struts/chain/contexts/ServletActionContext.java?view=auto&rev=151657
==============================================================================
--- struts/core/trunk/src/share/org/apache/struts/chain/contexts/ServletActionContext.java (added)
+++ struts/core/trunk/src/share/org/apache/struts/chain/contexts/ServletActionContext.java Sun Feb  6 17:42:35 2005
@@ -0,0 +1,189 @@
+/*
+ * $Id$ 
+ * 
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.chain.contexts;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.chain.web.servlet.ServletWebContext;
+import org.apache.struts.Globals;
+import org.apache.struts.action.ActionMessages;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.chain.Constants;
+import org.apache.struts.config.ActionConfig;
+import org.apache.struts.util.MessageResources;
+
+/**
+ * Implement ActionContext interface while making Servlet API-specific 
+ * values available.
+ */
+public class ServletActionContext extends WebActionContext {
+
+    public ServletActionContext(ServletWebContext context) {
+        super(context);
+    }
+
+    protected ServletWebContext swcontext() {
+        return (ServletWebContext) this.getBaseContext();
+    }
+
+    // -------------------------------
+    // Servlet specific properties
+    // -------------------------------
+    public ServletContext getContext()
+    {
+        return swcontext().getContext();
+    }
+
+    public HttpServletRequest getRequest()
+    {
+        return swcontext().getRequest();
+    }
+
+    public HttpServletResponse getResponse()
+    {
+        return swcontext().getResponse();
+    }
+
+    public ActionServlet getActionServlet() {
+        return (ActionServlet) this.get(Constants.ACTION_SERVLET_KEY);
+    }
+
+    public void setActionServlet(ActionServlet servlet) {
+        this.put(Constants.ACTION_SERVLET_KEY, servlet);
+    }
+
+    // -------------------------------
+    // Servlet specific modifications to base properties.
+    // -------------------------------
+    public void setActionConfig(ActionConfig actionConfig) {
+        super.setActionConfig(actionConfig);
+        this.getRequestScope().put(Globals.MAPPING_KEY, actionConfig);
+    }
+
+    public MessageResources getResources() {
+        return ((MessageResources) getRequest().getAttribute(Globals.MESSAGES_KEY));
+
+    }
+
+    public MessageResources getResources(String key) {
+        // Identify the current module
+        ServletContext context = getActionServlet().getServletContext();
+
+        // Return the requested message resources instance
+        /** @todo This method would probably be better handled by a "Struts"
+         * object which encapsulated the servler (Application) scope. */
+        return (MessageResources) context.getAttribute(key + getModuleConfig().getPrefix());
+
+    }
+
+    public void setResources(MessageResources resources) {
+        super.setResources(resources);
+        this.getRequest().setAttribute(Globals.MESSAGES_KEY, resources);
+    }
+
+    public void setResources(String key, MessageResources resources) {
+        this.getRequest().setAttribute(key + getModuleConfig().getPrefix(), resources);
+    }
+
+    // -------------------------------
+    // ActionMessage Processing
+    // -------------------------------
+    public void saveErrors(ActionMessages errors) {
+
+        // Remove any error messages attribute if none are required
+        if ((errors == null) || errors.isEmpty()) {
+            getRequest().removeAttribute(Globals.ERROR_KEY);
+            return;
+        }
+
+        // Save the error messages we need
+        getRequest().setAttribute(Globals.ERROR_KEY, errors);
+
+    }
+
+    public void saveMessages(ActionMessages messages) {
+
+        if ((messages == null) || messages.isEmpty()) {
+            getRequest().removeAttribute(Globals.MESSAGE_KEY);
+            return;
+        }
+        getRequest().setAttribute(Globals.MESSAGE_KEY, messages);
+    }
+
+    public void addMessages(ActionMessages messages) {
+
+            if (messages == null) return;
+
+            ActionMessages requestMessages = getMessages();
+            if (requestMessages == null){
+                    requestMessages = new ActionMessages();
+            }
+            requestMessages.add(messages);
+            saveMessages(requestMessages);
+    }
+
+
+    public void addErrors(ActionMessages errors) {
+
+            if (errors == null) return;
+
+            ActionMessages requestErrors = getErrors();
+            if (requestErrors == null){
+                    requestErrors = new ActionMessages();
+            }
+            requestErrors.add(errors);
+            saveErrors(requestErrors);
+    }
+
+    public ActionMessages getErrors() {
+        return (ActionMessages) this.getRequest().getAttribute(Globals.ERROR_KEY);
+    }
+
+    public ActionMessages getMessages() {
+        return (ActionMessages) this.getRequest().getAttribute(Globals.MESSAGE_KEY);
+    }
+
+    // -------------------------------
+    // Token Processing
+    // Implementing the servlet-aware versions by using the TokenProcessor class
+    // directly should ensure greater compatibility.
+    // -------------------------------
+
+    public void saveToken() {
+        token.saveToken(getRequest());
+    }
+
+    public String generateToken() {
+        return token.generateToken(getRequest());
+
+    }
+
+    public boolean isTokenValid(boolean reset) {
+        return token.isTokenValid(getRequest(), reset);
+    }
+
+    public void resetToken() {
+        token.resetToken(getRequest());
+    }
+
+
+    
+
+}
\ No newline at end of file

Added: struts/core/trunk/src/share/org/apache/struts/chain/contexts/WebActionContext.java
URL: http://svn.apache.org/viewcvs/struts/core/trunk/src/share/org/apache/struts/chain/contexts/WebActionContext.java?view=auto&rev=151657
==============================================================================
--- struts/core/trunk/src/share/org/apache/struts/chain/contexts/WebActionContext.java (added)
+++ struts/core/trunk/src/share/org/apache/struts/chain/contexts/WebActionContext.java Sun Feb  6 17:42:35 2005
@@ -0,0 +1,149 @@
+/*
+ * $Id$ 
+ * 
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts.chain.contexts;
+
+
+import java.util.Map;
+import org.apache.struts.config.ModuleConfig;
+import org.apache.struts.Globals;
+import org.apache.struts.util.MessageResources;
+import org.apache.commons.chain.web.WebContext;
+
+/**
+ * Subclass of ActionContextBase which is understood to be wrapping 
+ * an instance of <code>org.apache.commons.chain.web.WebContext</code>.
+ */
+public class WebActionContext extends ActionContextBase {
+
+    public WebActionContext(WebContext context) {
+        super(context);
+    }
+
+    protected WebContext wcontext() {
+        return (WebContext) this.getBaseContext();
+    }
+
+    public Map getApplicationScope()
+    {
+        return wcontext().getApplicationScope();
+    }
+
+    public Map getHeader()
+    {
+        return wcontext().getHeader();
+    }
+
+    public Map getHeaderValues()
+    {
+        return wcontext().getHeaderValues();
+    }
+
+    public Map getInitParam()
+    {
+        return wcontext().getInitParam();
+    }
+
+    public Map getParam()
+    {
+        return wcontext().getParam();
+    }
+
+    public Map getParamValues()
+    {
+        return wcontext().getParamValues();
+    }
+
+    public Map getRequestScope()
+    {
+        return wcontext().getRequestScope();
+    }
+
+    /**
+     * <p>Return the map returned by our nested <code>WebContext</code>'s 
+     * <code>getParamValues()</code> method. </p>
+     */
+    public Map getParameterMap()
+    {
+        return getParamValues();
+    }
+    
+    public Map getSessionScope()
+    {
+        return wcontext().getSessionScope();
+    }
+
+    /*
+     * @todo AbstractSelectModule set the precedent of doing this at the "web context" level
+     * instead of the ServletWebContext level.  Consider whether that's how we want to do it
+     * universally for other manipulations of the RequestScope or not...
+     */
+    public void setModuleConfig(ModuleConfig moduleConfig) {
+        super.setModuleConfig(moduleConfig);
+        this.getRequestScope().put(Globals.MODULE_KEY, moduleConfig);
+    }
+
+    /*
+     *  (non-Javadoc)
+     * Should thi
+     * @see org.apache.struts.chain.contexts.ActionContext#getModuleConfig()
+     */
+    public ModuleConfig getModuleConfig() {
+        ModuleConfig mc = super.getModuleConfig();
+        if (mc == null) {
+            mc = (ModuleConfig) this.getRequestScope().get(Globals.MODULE_KEY);
+        }
+        return mc;
+    }
+    
+    /*
+     * @todo AbstractSelectModule set the precedent of doing this at the "web context" level
+     * instead of the ServletWebContext level.  Consider whether that's how we want to do it
+     * universally for other manipulations of the RequestScope or not...
+     */
+    public void setResources(MessageResources messageResources) {
+        super.setMessageResources(messageResources);
+        this.getRequestScope().put(Globals.MESSAGES_KEY, messageResources);
+
+    }
+    
+    /*
+     * @todo AbstractSelectModule set the precedent of doing this at the "web context" level
+     * instead of the ServletWebContext level.  Consider whether that's how we want to do it
+     * universally for other manipulations of the RequestScope or not...
+     */
+    public void setCancelled(Boolean cancelled) {
+        super.setCancelled(cancelled);
+        // historic semantics of "isCancelled" are to consider any non-null
+        // value in the request under Globals.CANCEL_KEY as "yes, this was cancelled."
+        if (cancelled != null && cancelled.booleanValue()) {
+            this.getRequestScope().put(Globals.CANCEL_KEY, cancelled);
+        } else {
+            this.getRequestScope().remove(Globals.CANCEL_KEY);
+        }
+
+    }
+
+     
+    public Boolean getCancelled() {
+        Boolean c = super.getCancelled();
+        if (c == null) {
+            c = (Boolean) this.getRequestScope().get(Globals.CANCEL_KEY);
+        }
+        return c;
+    }
+}
\ No newline at end of file

Added: struts/core/trunk/src/test/org/apache/struts/chain/commands/generic/TestWrappingLookupCommand.java
URL: http://svn.apache.org/viewcvs/struts/core/trunk/src/test/org/apache/struts/chain/commands/generic/TestWrappingLookupCommand.java?view=auto&rev=151657
==============================================================================
--- struts/core/trunk/src/test/org/apache/struts/chain/commands/generic/TestWrappingLookupCommand.java (added)
+++ struts/core/trunk/src/test/org/apache/struts/chain/commands/generic/TestWrappingLookupCommand.java Sun Feb  6 17:42:35 2005
@@ -0,0 +1,77 @@
+/*
+ * $Id$ 
+ * 
+ * Copyright 2003,2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts.chain.commands.generic;
+
+import junit.framework.TestCase;
+import org.apache.commons.chain.Context;
+import org.apache.commons.chain.impl.ContextBase;
+import org.apache.commons.chain.web.servlet.ServletWebContext;
+import org.apache.struts.chain.contexts.ActionContextBase;
+import org.apache.struts.chain.contexts.ServletActionContext;
+
+/* JUnitTest case for class: org.apache.struts.chain.commands.generic.WrappingLookupCommand */
+public class TestWrappingLookupCommand extends TestCase {
+
+    public TestWrappingLookupCommand(String _name) {
+        super(_name);
+    }
+
+    /* setUp method for test case */
+    protected void setUp() {
+    }
+
+    /* tearDown method for test case */
+    protected void tearDown() {
+    }
+
+    public void testSame() throws Exception {
+        WrappingLookupCommand command = new WrappingLookupCommand();
+        Context testContext = new ContextBase();
+
+        Context wrapped = command.getContext(testContext);
+        assertNotNull(wrapped);
+        assertSame(testContext, wrapped);
+    }
+
+    public void testWrapper() throws Exception {
+        WrappingLookupCommand command = new WrappingLookupCommand();
+        command.setWrapperClassName(ActionContextBase.class.getName());
+        Context testContext = new ContextBase();
+
+        Context wrapped = command.getContext(testContext);
+        assertNotNull(wrapped);
+        assertTrue(wrapped instanceof ActionContextBase);
+    }
+
+    public void testWrapContextSubclass() throws Exception {
+        WrappingLookupCommand command = new WrappingLookupCommand();
+        command.setWrapperClassName(ServletActionContext.class.getName());
+        Context testContext = new ServletWebContext();
+
+        Context wrapped = command.getContext(testContext);
+        assertNotNull(wrapped);
+        assertTrue(wrapped instanceof ServletActionContext);
+    }
+
+    /* Executes the test case */
+    public static void main(String[] argv) {
+        String[] testCaseList = {TestWrappingLookupCommand.class.getName()};
+        junit.textui.TestRunner.main(testCaseList);
+    }
+}
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org