diff --git a/org.springframework.web.struts/build.xml b/org.springframework.web.struts/build.xml
new file mode 100644
index 00000000000..acfd7e6840c
--- /dev/null
+++ b/org.springframework.web.struts/build.xml
@@ -0,0 +1,6 @@
+
+
Derives from the Tiles {@link ControllerSupport} class rather than
+ * implementing the Tiles {@link org.apache.struts.tiles.Controller} interface
+ * in order to be compatible with Struts 1.1 and 1.2. Implements both Struts 1.1's
+ * perform and Struts 1.2's execute method accordingly.
+ *
+ * @author Juergen Hoeller
+ * @author Alef Arendsen
+ * @since 22.08.2003
+ * @see org.springframework.web.context.support.WebApplicationObjectSupport
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public abstract class ComponentControllerSupport extends ControllerSupport {
+
+ private WebApplicationContext webApplicationContext;
+
+ private MessageSourceAccessor messageSourceAccessor;
+
+
+ /**
+ * This implementation delegates to execute,
+ * converting non-Servlet/IO Exceptions to ServletException.
+ *
This is the only execution method available in Struts 1.1.
+ * @see #execute
+ */
+ @Override
+ public final void perform(
+ ComponentContext componentContext, HttpServletRequest request,
+ HttpServletResponse response, ServletContext servletContext)
+ throws ServletException, IOException {
+
+ try {
+ execute(componentContext, request, response, servletContext);
+ }
+ catch (ServletException ex) {
+ throw ex;
+ }
+ catch (IOException ex) {
+ throw ex;
+ }
+ catch (Throwable ex) {
+ throw new NestedServletException("Execution of component controller failed", ex);
+ }
+ }
+
+ /**
+ * This implementation delegates to doPerform,
+ * lazy-initializing the application context reference if necessary.
+ *
This is the preferred execution method in Struts 1.2.
+ * When running with Struts 1.1, it will be called by perform.
+ * @see #perform
+ * @see #doPerform
+ */
+ @Override
+ public final void execute(
+ ComponentContext componentContext, HttpServletRequest request,
+ HttpServletResponse response, ServletContext servletContext)
+ throws Exception {
+
+ synchronized (this) {
+ if (this.webApplicationContext == null) {
+ this.webApplicationContext = RequestContextUtils.getWebApplicationContext(request, servletContext);
+ this.messageSourceAccessor = new MessageSourceAccessor(this.webApplicationContext);
+ }
+ }
+ doPerform(componentContext, request, response);
+ }
+
+
+ /**
+ * Subclasses can override this for custom initialization behavior.
+ * Gets called on initialization of the context for this controller.
+ * @throws org.springframework.context.ApplicationContextException in case of initialization errors
+ * @throws org.springframework.beans.BeansException if thrown by application context methods
+ */
+ protected void initApplicationContext() throws BeansException {
+ }
+
+ /**
+ * Return the current Spring ApplicationContext.
+ */
+ protected final ApplicationContext getApplicationContext() {
+ return this.webApplicationContext;
+ }
+
+ /**
+ * Return the current Spring WebApplicationContext.
+ */
+ protected final WebApplicationContext getWebApplicationContext() {
+ return this.webApplicationContext;
+ }
+
+ /**
+ * Return a MessageSourceAccessor for the application context
+ * used by this object, for easy message access.
+ */
+ protected final MessageSourceAccessor getMessageSourceAccessor() {
+ return this.messageSourceAccessor;
+ }
+
+ /**
+ * Return the current ServletContext.
+ */
+ protected final ServletContext getServletContext() {
+ return this.webApplicationContext.getServletContext();
+ }
+
+ /**
+ * Return the temporary directory for the current web application,
+ * as provided by the servlet container.
+ * @return the File representing the temporary directory
+ */
+ protected final File getTempDir() {
+ return WebUtils.getTempDir(getServletContext());
+ }
+
+
+ /**
+ * Perform the preparation for the component, allowing for any Exception to be thrown.
+ * The ServletContext can be retrieved via getServletContext, if necessary.
+ * The Spring WebApplicationContext can be accessed via getWebApplicationContext.
+ *
This method will be called both in the Struts 1.1 and Struts 1.2 case,
+ * by perform or execute, respectively.
+ * @param componentContext current Tiles component context
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @throws Exception in case of errors
+ * @see org.apache.struts.tiles.Controller#perform
+ * @see #getServletContext
+ * @see #getWebApplicationContext
+ * @see #perform
+ * @see #execute
+ */
+ protected abstract void doPerform(
+ ComponentContext componentContext, HttpServletRequest request, HttpServletResponse response)
+ throws Exception;
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/TilesConfigurer.java b/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/TilesConfigurer.java
new file mode 100644
index 00000000000..3ac220ce339
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/TilesConfigurer.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * 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.springframework.web.servlet.view.tiles;
+
+import org.apache.struts.tiles.DefinitionsFactory;
+import org.apache.struts.tiles.DefinitionsFactoryConfig;
+import org.apache.struts.tiles.DefinitionsFactoryException;
+import org.apache.struts.tiles.TilesUtil;
+import org.apache.struts.tiles.xmlDefinition.I18nFactorySet;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.StringUtils;
+import org.springframework.web.context.support.WebApplicationObjectSupport;
+
+/**
+ * Helper class to configure Tiles 1.x for the Spring Framework. See
+ * http://struts.apache.org
+ * for more information about Struts Tiles, which basically is a templating
+ * mechanism for JSP-based web applications.
+ *
+ *
NOTE: This TilesConfigurer class supports Tiles 1.x, + * a.k.a. "Struts Tiles", which comes as part of Struts 1.x. + * For Tiles 2.x support, check out + * {@link org.springframework.web.servlet.view.tiles2.TilesConfigurer}. + * + *
The TilesConfigurer simply configures a Tiles DefinitionsFactory using + * a set of files containing definitions, to be accessed by {@link TilesView} + * instances. + * + *
TilesViews can be managed by any {@link org.springframework.web.servlet.ViewResolver}. + * For simple convention-based view resolution, consider using + * {@link org.springframework.web.servlet.view.UrlBasedViewResolver} with the + * "viewClass" property set to "org.springframework.web.servlet.view.tiles.TilesView". + * + *
A typical TilesConfigurer bean definition looks as follows: + * + *
+ * <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles.TilesConfigurer"> + * <property name="definitions"> + * <list> + * <value>/WEB-INF/defs/general.xml</value> + * <value>/WEB-INF/defs/widgets.xml</value> + * <value>/WEB-INF/defs/administrator.xml</value> + * <value>/WEB-INF/defs/customer.xml</value> + * <value>/WEB-INF/defs/templates.xml</value> + * </list> + * </property> + * </bean>+ * + * The values in the list are the actual files containing the definitions. + * + * @author Alef Arendsen + * @author Juergen Hoeller + * @see TilesView + * @see org.springframework.web.servlet.view.UrlBasedViewResolver + * @deprecated as of Spring 3.0 + */ +@Deprecated +public class TilesConfigurer extends WebApplicationObjectSupport implements InitializingBean { + + /** Definition URLs mapped to descriptions */ + private String[] definitions; + + /** Validate the Tiles definitions? */ + private boolean validateDefinitions = true; + + /** Factory class for Tiles */ + private Class factoryClass = I18nFactorySet.class; + + + /** + * Set the Tiles definitions, i.e. the list of files containing the definitions. + */ + public void setDefinitions(String[] definitions) { + this.definitions = definitions; + } + + /** + * Set whether to validate the Tiles XML definitions. Default is "true". + */ + public void setValidateDefinitions(boolean validateDefinitions) { + this.validateDefinitions = validateDefinitions; + } + + /** + * Set the factory class for Tiles. Default is I18nFactorySet. + * @see org.apache.struts.tiles.xmlDefinition.I18nFactorySet + */ + public void setFactoryClass(Class factoryClass) { + this.factoryClass = factoryClass; + } + + + /** + * Initialize the Tiles definition factory. + * Delegates to createDefinitionsFactory for the actual creation. + * @throws DefinitionsFactoryException if an error occurs + * @see #createDefinitionsFactory + */ + public void afterPropertiesSet() throws DefinitionsFactoryException { + logger.debug("TilesConfigurer: initializion started"); + + // initialize the configuration for the definitions factory + DefinitionsFactoryConfig factoryConfig = new DefinitionsFactoryConfig(); + factoryConfig.setFactoryName(""); + factoryConfig.setFactoryClassname(this.factoryClass.getName()); + factoryConfig.setParserValidate(this.validateDefinitions); + + if (this.definitions != null) { + String defs = StringUtils.arrayToCommaDelimitedString(this.definitions); + if (logger.isInfoEnabled()) { + logger.info("TilesConfigurer: adding definitions [" + defs + "]"); + } + factoryConfig.setDefinitionConfigFiles(defs); + } + + // initialize the definitions factory + createDefinitionsFactory(factoryConfig); + + logger.debug("TilesConfigurer: initialization completed"); + } + + /** + * Create the Tiles DefinitionsFactory and expose it to the ServletContext. + * @param factoryConfig the configuration for the DefinitionsFactory + * @return the DefinitionsFactory + * @throws DefinitionsFactoryException if an error occurs + */ + protected DefinitionsFactory createDefinitionsFactory(DefinitionsFactoryConfig factoryConfig) + throws DefinitionsFactoryException { + + return TilesUtil.createDefinitionsFactory(getServletContext(), factoryConfig); + } + +} diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/TilesJstlView.java b/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/TilesJstlView.java new file mode 100644 index 00000000000..232f1b49ff0 --- /dev/null +++ b/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/TilesJstlView.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * 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.springframework.web.servlet.view.tiles; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.web.servlet.support.JstlUtils; +import org.springframework.web.servlet.support.RequestContext; + +/** + * Specialization of {@link TilesView} for JSTL pages, + * i.e. Tiles pages that use the JSP Standard Tag Library. + * + *
NOTE: This TilesJstlView class supports Tiles 1.x, + * a.k.a. "Struts Tiles", which comes as part of Struts 1.x. + * For Tiles 2.x support, check out + * {@link org.springframework.web.servlet.view.tiles2.TilesView}. + * + *
Exposes JSTL-specific request attributes specifying locale + * and resource bundle for JSTL's formatting and message tags, + * using Spring's locale and message source. + * + *
This is a separate class mainly to avoid JSTL dependencies + * in TilesView itself. + * + * @author Juergen Hoeller + * @since 20.08.2003 + * @see org.springframework.web.servlet.support.JstlUtils#exposeLocalizationContext + * @deprecated as of Spring 3.0 + */ +@Deprecated +public class TilesJstlView extends TilesView { + + @Override + protected void exposeHelpers(HttpServletRequest request) throws Exception { + JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext())); + } + +} diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/TilesView.java b/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/TilesView.java new file mode 100644 index 00000000000..2ec68703757 --- /dev/null +++ b/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/TilesView.java @@ -0,0 +1,209 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * 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.springframework.web.servlet.view.tiles; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.struts.tiles.ComponentContext; +import org.apache.struts.tiles.ComponentDefinition; +import org.apache.struts.tiles.Controller; +import org.apache.struts.tiles.DefinitionsFactory; +import org.apache.struts.tiles.TilesUtilImpl; + +import org.springframework.context.ApplicationContextException; +import org.springframework.web.servlet.view.InternalResourceView; + +/** + * View implementation that retrieves a Tiles definition. + * The "url" property is interpreted as name of a Tiles definition. + * + *
{@link TilesJstlView} with JSTL support is a separate class, + * mainly to avoid JSTL dependencies in this class. + * + *
NOTE: This TilesView class supports Tiles 1.x, + * a.k.a. "Struts Tiles", which comes as part of Struts 1.x. + * For Tiles 2.x support, check out + * {@link org.springframework.web.servlet.view.tiles2.TilesView}. + * + *
Depends on a Tiles DefinitionsFactory which must be available + * in the ServletContext. This factory is typically set up via a + * {@link TilesConfigurer} bean definition in the application context. + * + *
Check out {@link ComponentControllerSupport} which provides
+ * a convenient base class for Spring-aware component controllers,
+ * allowing convenient access to the Spring ApplicationContext.
+ *
+ * @author Alef Arendsen
+ * @author Juergen Hoeller
+ * @see #setUrl
+ * @see TilesJstlView
+ * @see TilesConfigurer
+ * @see ComponentControllerSupport
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public class TilesView extends InternalResourceView {
+
+ /**
+ * Name of the attribute that will override the path of the layout page
+ * to render. A Tiles component controller can set such an attribute
+ * to dynamically switch the look and feel of a Tiles page.
+ * @see #setPath
+ */
+ public static final String PATH_ATTRIBUTE = TilesView.class.getName() + ".PATH";
+
+ /**
+ * Set the path of the layout page to render.
+ * @param request current HTTP request
+ * @param path the path of the layout page
+ * @see #PATH_ATTRIBUTE
+ */
+ public static void setPath(HttpServletRequest request, String path) {
+ request.setAttribute(PATH_ATTRIBUTE, path);
+ }
+
+
+ private DefinitionsFactory definitionsFactory;
+
+
+ @Override
+ protected void initApplicationContext() throws ApplicationContextException {
+ super.initApplicationContext();
+
+ // get definitions factory
+ this.definitionsFactory =
+ (DefinitionsFactory) getServletContext().getAttribute(TilesUtilImpl.DEFINITIONS_FACTORY);
+ if (this.definitionsFactory == null) {
+ throw new ApplicationContextException("Tiles definitions factory not found: TilesConfigurer not defined?");
+ }
+ }
+
+ /**
+ * Prepare for rendering the Tiles definition: Execute the associated
+ * component controller if any, and determine the request dispatcher path.
+ */
+ @Override
+ protected String prepareForRendering(HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+
+ // get component definition
+ ComponentDefinition definition = getComponentDefinition(this.definitionsFactory, request);
+ if (definition == null) {
+ throw new ServletException("No Tiles definition found for name '" + getUrl() + "'");
+ }
+
+ // get current component context
+ ComponentContext context = getComponentContext(definition, request);
+
+ // execute component controller associated with definition, if any
+ Controller controller = getController(definition, request);
+ if (controller != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Executing Tiles controller [" + controller + "]");
+ }
+ executeController(controller, context, request, response);
+ }
+
+ // determine the path of the definition
+ String path = getDispatcherPath(definition, request);
+ if (path == null) {
+ throw new ServletException(
+ "Could not determine a path for Tiles definition '" + definition.getName() + "'");
+ }
+
+ return path;
+ }
+
+ /**
+ * Determine the Tiles component definition for the given Tiles
+ * definitions factory.
+ * @param factory the Tiles definitions factory
+ * @param request current HTTP request
+ * @return the component definition
+ */
+ protected ComponentDefinition getComponentDefinition(DefinitionsFactory factory, HttpServletRequest request)
+ throws Exception {
+ return factory.getDefinition(getUrl(), request, getServletContext());
+ }
+
+ /**
+ * Determine the Tiles component context for the given Tiles definition.
+ * @param definition the Tiles definition to render
+ * @param request current HTTP request
+ * @return the component context
+ * @throws Exception if preparations failed
+ */
+ protected ComponentContext getComponentContext(ComponentDefinition definition, HttpServletRequest request)
+ throws Exception {
+ ComponentContext context = ComponentContext.getContext(request);
+ if (context == null) {
+ context = new ComponentContext(definition.getAttributes());
+ ComponentContext.setContext(context, request);
+ }
+ else {
+ context.addMissing(definition.getAttributes());
+ }
+ return context;
+ }
+
+ /**
+ * Determine and initialize the Tiles component controller for the
+ * given Tiles definition, if any.
+ * @param definition the Tiles definition to render
+ * @param request current HTTP request
+ * @return the component controller to execute, or null if none
+ * @throws Exception if preparations failed
+ */
+ protected Controller getController(ComponentDefinition definition, HttpServletRequest request)
+ throws Exception {
+
+ return definition.getOrCreateController();
+ }
+
+ /**
+ * Execute the given Tiles controller.
+ * @param controller the component controller to execute
+ * @param context the component context
+ * @param request current HTTP request
+ * @param response current HTTP response
+ * @throws Exception if controller execution failed
+ */
+ protected void executeController(
+ Controller controller, ComponentContext context, HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+
+ controller.perform(context, request, response, getServletContext());
+ }
+
+ /**
+ * Determine the dispatcher path for the given Tiles definition,
+ * i.e. the request dispatcher path of the layout page.
+ * @param definition the Tiles definition to render
+ * @param request current HTTP request
+ * @return the path of the layout page to render
+ * @throws Exception if preparations failed
+ */
+ protected String getDispatcherPath(ComponentDefinition definition, HttpServletRequest request)
+ throws Exception {
+
+ Object pathAttr = request.getAttribute(PATH_ATTRIBUTE);
+ return (pathAttr != null ? pathAttr.toString() : definition.getPath());
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/package.html b/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/package.html
new file mode 100644
index 00000000000..4320c5f3eaf
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/servlet/view/tiles/package.html
@@ -0,0 +1,10 @@
+
+
Action.setServlet with null on
+ * bean destruction, providing the same lifecycle handling as the
+ * native Struts ActionServlet.
+ *
+ * ContextLoaderPlugIn automatically registers this processor
+ * with the underlying bean factory of its WebApplicationContext.
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.1
+ * @see ContextLoaderPlugIn
+ * @see org.apache.struts.action.Action#setServlet
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+class ActionServletAwareProcessor implements DestructionAwareBeanPostProcessor {
+
+ private final ActionServlet actionServlet;
+
+
+ /**
+ * Create a new ActionServletAwareProcessor for the given servlet.
+ */
+ public ActionServletAwareProcessor(ActionServlet actionServlet) {
+ this.actionServlet = actionServlet;
+ }
+
+
+ public Object postProcessBeforeInitialization(Object bean, String beanName) {
+ if (bean instanceof Action) {
+ ((Action) bean).setServlet(this.actionServlet);
+ }
+ return bean;
+ }
+
+ public Object postProcessAfterInitialization(Object bean, String beanName) {
+ return bean;
+ }
+
+ public void postProcessBeforeDestruction(Object bean, String beanName) {
+ if (bean instanceof Action) {
+ ((Action) bean).setServlet(null);
+ }
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/ActionSupport.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/ActionSupport.java
new file mode 100644
index 00000000000..1630b30c77a
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/ActionSupport.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2002-2005 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.io.File;
+
+import javax.servlet.ServletContext;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionServlet;
+
+import org.springframework.context.support.MessageSourceAccessor;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.util.WebUtils;
+
+/**
+ * Convenience class for Spring-aware Struts 1.1+ Actions.
+ *
+ *
Provides a reference to the current Spring application context, e.g.
+ * for bean lookup or resource loading. Auto-detects a ContextLoaderPlugIn
+ * context, falling back to the root WebApplicationContext. For typical
+ * usage, i.e. accessing middle tier beans, use a root WebApplicationContext.
+ *
+ *
For Struts DispatchActions or Lookup/MappingDispatchActions, use the
+ * analogous {@link DispatchActionSupport DispatchActionSupport} or
+ * {@link LookupDispatchActionSupport LookupDispatchActionSupport} /
+ * {@link MappingDispatchActionSupport MappingDispatchActionSupport} class,
+ * respectively.
+ *
+ *
As an alternative approach, you can wire your Struts Actions themselves
+ * as Spring beans, passing references to them via IoC rather than looking
+ * up references in a programmatic fashion. Check out
+ * {@link DelegatingActionProxy DelegatingActionProxy} and
+ * {@link DelegatingRequestProcessor DelegatingRequestProcessor}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.1
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
+ * @see org.springframework.web.context.ContextLoaderListener
+ * @see org.springframework.web.context.ContextLoaderServlet
+ * @see DispatchActionSupport
+ * @see LookupDispatchActionSupport
+ * @see MappingDispatchActionSupport
+ * @see DelegatingActionProxy
+ * @see DelegatingRequestProcessor
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public abstract class ActionSupport extends Action {
+
+ private WebApplicationContext webApplicationContext;
+
+ private MessageSourceAccessor messageSourceAccessor;
+
+
+ /**
+ * Initialize the WebApplicationContext for this Action.
+ * Invokes onInit after successful initialization of the context.
+ * @see #initWebApplicationContext
+ * @see #onInit
+ */
+ @Override
+ public void setServlet(ActionServlet actionServlet) {
+ super.setServlet(actionServlet);
+ if (actionServlet != null) {
+ this.webApplicationContext = initWebApplicationContext(actionServlet);
+ this.messageSourceAccessor = new MessageSourceAccessor(this.webApplicationContext);
+ onInit();
+ }
+ else {
+ onDestroy();
+ }
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's WebApplicationContext from the ServletContext,
+ * falling back to the root WebApplicationContext (the usual case).
+ * @param actionServlet the associated ActionServlet
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see DelegatingActionUtils#findRequiredWebApplicationContext
+ */
+ protected WebApplicationContext initWebApplicationContext(ActionServlet actionServlet)
+ throws IllegalStateException {
+
+ return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, null);
+ }
+
+
+ /**
+ * Return the current Spring WebApplicationContext.
+ */
+ protected final WebApplicationContext getWebApplicationContext() {
+ return this.webApplicationContext;
+ }
+
+ /**
+ * Return a MessageSourceAccessor for the application context
+ * used by this object, for easy message access.
+ */
+ protected final MessageSourceAccessor getMessageSourceAccessor() {
+ return this.messageSourceAccessor;
+ }
+
+ /**
+ * Return the current ServletContext.
+ */
+ protected final ServletContext getServletContext() {
+ return this.webApplicationContext.getServletContext();
+ }
+
+ /**
+ * Return the temporary directory for the current web application,
+ * as provided by the servlet container.
+ * @return the File representing the temporary directory
+ */
+ protected final File getTempDir() {
+ return WebUtils.getTempDir(getServletContext());
+ }
+
+
+ /**
+ * Callback for custom initialization after the context has been set up.
+ * @see #setServlet
+ */
+ protected void onInit() {
+ }
+
+ /**
+ * Callback for custom destruction when the ActionServlet shuts down.
+ * @see #setServlet
+ */
+ protected void onDestroy() {
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/AutowiringRequestProcessor.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/AutowiringRequestProcessor.java
new file mode 100644
index 00000000000..f14091729d9
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/AutowiringRequestProcessor.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2002-2006 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.action.RequestProcessor;
+import org.apache.struts.config.ModuleConfig;
+
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * Subclass of Struts's default RequestProcessor that autowires Struts Actions
+ * with Spring beans defined in ContextLoaderPlugIn's WebApplicationContext
+ * or - in case of general service layer beans - in the root WebApplicationContext.
+ *
+ *
In the Struts config file, you simply continue to specify the original
+ * Action class. The instance created for that class will automatically get
+ * wired with matching service layer beans, that is, bean property setters
+ * will automatically be called if a service layer bean matches the property.
+ *
+ *
+ * <action path="/login" type="myapp.MyAction"/>
+ *
+ * There are two autowire modes available: "byType" and "byName". The default
+ * is "byType", matching service layer beans with the Action's bean property
+ * argument types. This behavior can be changed through specifying an "autowire"
+ * init-param for the Struts ActionServlet with the value "byName", which will
+ * match service layer bean names with the Action's bean property names.
+ *
+ * Dependency checking is turned off by default: If no matching service
+ * layer bean can be found, the setter in question will simply not get invoked.
+ * To enforce matching service layer beans, consider specify the "dependencyCheck"
+ * init-param for the Struts ActionServlet with the value "true".
+ *
+ *
If you also need the Tiles setup functionality of the original
+ * TilesRequestProcessor, use AutowiringTilesRequestProcessor. As there's just
+ * a single central class to customize in Struts, we have to provide another
+ * subclass here, covering both the Tiles and the Spring delegation aspect.
+ *
+ *
The default implementation delegates to the DelegatingActionUtils
+ * class as fas as possible, to reuse as much code as possible despite
+ * the need to provide two RequestProcessor subclasses. If you need to
+ * subclass yet another RequestProcessor, take this class as a template,
+ * delegating to DelegatingActionUtils just like it.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see AutowiringTilesRequestProcessor
+ * @see ContextLoaderPlugIn
+ * @see DelegatingActionUtils
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public class AutowiringRequestProcessor extends RequestProcessor {
+
+ private WebApplicationContext webApplicationContext;
+
+ private int autowireMode = AutowireCapableBeanFactory.AUTOWIRE_NO;
+
+ private boolean dependencyCheck = false;
+
+
+ @Override
+ public void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException {
+ super.init(actionServlet, moduleConfig);
+ if (actionServlet != null) {
+ this.webApplicationContext = initWebApplicationContext(actionServlet, moduleConfig);
+ this.autowireMode = initAutowireMode(actionServlet, moduleConfig);
+ this.dependencyCheck = initDependencyCheck(actionServlet, moduleConfig);
+ }
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's WebApplicationContext from the ServletContext,
+ * falling back to the root WebApplicationContext. This context is supposed
+ * to contain the service layer beans to wire the Struts Actions with.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see DelegatingActionUtils#findRequiredWebApplicationContext
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ */
+ protected WebApplicationContext initWebApplicationContext(
+ ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
+
+ WebApplicationContext wac =
+ DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, moduleConfig);
+ if (wac instanceof ConfigurableApplicationContext) {
+ ((ConfigurableApplicationContext) wac).getBeanFactory().ignoreDependencyType(ActionServlet.class);
+ }
+ return wac;
+ }
+
+ /**
+ * Determine the autowire mode to use for wiring Struts Actions.
+ *
The default implementation checks the "autowire" init-param of the
+ * Struts ActionServlet, falling back to "AUTOWIRE_BY_TYPE" as default.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig
+ * @return the autowire mode to use
+ * @see DelegatingActionUtils#getAutowireMode
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBeanProperties
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#AUTOWIRE_BY_TYPE
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#AUTOWIRE_BY_NAME
+ */
+ protected int initAutowireMode(ActionServlet actionServlet, ModuleConfig moduleConfig) {
+ return DelegatingActionUtils.getAutowireMode(actionServlet);
+ }
+
+ /**
+ * Determine whether to apply a dependency check after wiring Struts Actions.
+ *
The default implementation checks the "dependencyCheck" init-param of the
+ * Struts ActionServlet, falling back to no dependency check as default.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig
+ * @return whether to enforce a dependency check or not
+ * @see DelegatingActionUtils#getDependencyCheck
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBeanProperties
+ */
+ protected boolean initDependencyCheck(ActionServlet actionServlet, ModuleConfig moduleConfig) {
+ return DelegatingActionUtils.getDependencyCheck(actionServlet);
+ }
+
+
+ /**
+ * Return the current Spring WebApplicationContext.
+ */
+ protected final WebApplicationContext getWebApplicationContext() {
+ return this.webApplicationContext;
+ }
+
+ /**
+ * Return the autowire mode to use for wiring Struts Actions.
+ */
+ protected final int getAutowireMode() {
+ return autowireMode;
+ }
+
+ /**
+ * Return whether to apply a dependency check after wiring Struts Actions.
+ */
+ protected final boolean getDependencyCheck() {
+ return dependencyCheck;
+ }
+
+
+ /**
+ * Extend the base class method to autowire each created Action instance.
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBeanProperties
+ */
+ @Override
+ protected Action processActionCreate(
+ HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
+ throws IOException {
+
+ Action action = super.processActionCreate(request, response, mapping);
+ getWebApplicationContext().getAutowireCapableBeanFactory().autowireBeanProperties(
+ action, getAutowireMode(), getDependencyCheck());
+ return action;
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/AutowiringTilesRequestProcessor.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/AutowiringTilesRequestProcessor.java
new file mode 100644
index 00000000000..96a24c8c6e8
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/AutowiringTilesRequestProcessor.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2002-2006 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.config.ModuleConfig;
+import org.apache.struts.tiles.TilesRequestProcessor;
+
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * Subclass of Struts's TilesRequestProcessor that autowires Struts Actions
+ * with Spring beans defined in ContextLoaderPlugIn's WebApplicationContext
+ * or - in case of general service layer beans - in the root WebApplicationContext.
+ *
+ *
Behaves like
+ * {@link AutowiringRequestProcessor AutowiringRequestProcessor},
+ * but also provides the Tiles functionality of the original TilesRequestProcessor.
+ * As there's just a single central class to customize in Struts, we have to provide
+ * another subclass here, covering both the Tiles and the Spring delegation aspect.
+ *
+ *
The default implementation delegates to the DelegatingActionUtils
+ * class as fas as possible, to reuse as much code as possible despite
+ * the need to provide two RequestProcessor subclasses. If you need to
+ * subclass yet another RequestProcessor, take this class as a template,
+ * delegating to DelegatingActionUtils just like it.
+ *
+ * @author Juergen Hoeller
+ * @since 2.0
+ * @see AutowiringRequestProcessor
+ * @see ContextLoaderPlugIn
+ * @see DelegatingActionUtils
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public class AutowiringTilesRequestProcessor extends TilesRequestProcessor {
+
+ private WebApplicationContext webApplicationContext;
+
+ private int autowireMode = AutowireCapableBeanFactory.AUTOWIRE_NO;
+
+ private boolean dependencyCheck = false;
+
+
+ @Override
+ public void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException {
+ super.init(actionServlet, moduleConfig);
+ if (actionServlet != null) {
+ this.webApplicationContext = initWebApplicationContext(actionServlet, moduleConfig);
+ this.autowireMode = initAutowireMode(actionServlet, moduleConfig);
+ this.dependencyCheck = initDependencyCheck(actionServlet, moduleConfig);
+ }
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's WebApplicationContext from the ServletContext,
+ * falling back to the root WebApplicationContext. This context is supposed
+ * to contain the service layer beans to wire the Struts Actions with.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see DelegatingActionUtils#findRequiredWebApplicationContext
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ */
+ protected WebApplicationContext initWebApplicationContext(
+ ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
+
+ WebApplicationContext wac =
+ DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, moduleConfig);
+ if (wac instanceof ConfigurableApplicationContext) {
+ ((ConfigurableApplicationContext) wac).getBeanFactory().ignoreDependencyType(ActionServlet.class);
+ }
+ return wac;
+ }
+
+ /**
+ * Determine the autowire mode to use for wiring Struts Actions.
+ *
The default implementation checks the "autowire" init-param of the
+ * Struts ActionServlet, falling back to "AUTOWIRE_BY_TYPE" as default.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig
+ * @return the autowire mode to use
+ * @see DelegatingActionUtils#getAutowireMode
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBeanProperties
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#AUTOWIRE_BY_TYPE
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#AUTOWIRE_BY_NAME
+ */
+ protected int initAutowireMode(ActionServlet actionServlet, ModuleConfig moduleConfig) {
+ return DelegatingActionUtils.getAutowireMode(actionServlet);
+ }
+
+ /**
+ * Determine whether to apply a dependency check after wiring Struts Actions.
+ *
The default implementation checks the "dependencyCheck" init-param of the
+ * Struts ActionServlet, falling back to no dependency check as default.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig
+ * @return whether to enforce a dependency check or not
+ * @see DelegatingActionUtils#getDependencyCheck
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBeanProperties
+ */
+ protected boolean initDependencyCheck(ActionServlet actionServlet, ModuleConfig moduleConfig) {
+ return DelegatingActionUtils.getDependencyCheck(actionServlet);
+ }
+
+
+ /**
+ * Return the current Spring WebApplicationContext.
+ */
+ protected final WebApplicationContext getWebApplicationContext() {
+ return this.webApplicationContext;
+ }
+
+ /**
+ * Return the autowire mode to use for wiring Struts Actions.
+ */
+ protected final int getAutowireMode() {
+ return autowireMode;
+ }
+
+ /**
+ * Return whether to apply a dependency check after wiring Struts Actions.
+ */
+ protected final boolean getDependencyCheck() {
+ return dependencyCheck;
+ }
+
+
+ /**
+ * Extend the base class method to autowire each created Action instance.
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBeanProperties
+ */
+ @Override
+ protected Action processActionCreate(
+ HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
+ throws IOException {
+
+ Action action = super.processActionCreate(request, response, mapping);
+ getWebApplicationContext().getAutowireCapableBeanFactory().autowireBeanProperties(
+ action, getAutowireMode(), getDependencyCheck());
+ return action;
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/ContextLoaderPlugIn.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/ContextLoaderPlugIn.java
new file mode 100644
index 00000000000..24317165dbc
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/ContextLoaderPlugIn.java
@@ -0,0 +1,397 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.action.PlugIn;
+import org.apache.struts.config.ModuleConfig;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.ApplicationContextException;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.context.ConfigurableWebApplicationContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+import org.springframework.web.context.support.XmlWebApplicationContext;
+
+/**
+ * Struts 1.1+ PlugIn that loads a Spring application context for the Struts
+ * ActionServlet. This context will automatically refer to the root
+ * WebApplicationContext (loaded by ContextLoaderListener/Servlet) as parent.
+ *
+ *
The default namespace of the WebApplicationContext is the name of the
+ * Struts ActionServlet, suffixed with "-servlet" (e.g. "action-servlet").
+ * The default location of the XmlWebApplicationContext configuration file
+ * is therefore "/WEB-INF/action-servlet.xml".
+ *
+ *
+ * <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"/>
+ *
+ * The location of the context configuration files can be customized
+ * through the "contextConfigLocation" setting, analogous to the root
+ * WebApplicationContext and FrameworkServlet contexts.
+ *
+ *
+ * <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
+ * <set-property property="contextConfigLocation" value="/WEB-INF/action-servlet.xml /WEB-INF/myContext.xml"/>
+ * </plug-in>
+ *
+ * Beans defined in the ContextLoaderPlugIn context can be accessed
+ * from conventional Struts Actions, via fetching the WebApplicationContext
+ * reference from the ServletContext. ActionSupport and DispatchActionSupport
+ * are pre-built convenience classes that provide easy access to the context.
+ *
+ * It is normally preferable to access Spring's root WebApplicationContext
+ * in such scenarios, though: A shared middle tier should be defined there
+ * rather than in a ContextLoaderPlugin context, for access by any web component.
+ * ActionSupport and DispatchActionSupport autodetect the root context too.
+ *
+ *
A special usage of this PlugIn is to define Struts Actions themselves
+ * as beans, typically wiring them with middle tier components defined in the
+ * root context. Such Actions will then be delegated to by proxy definitions
+ * in the Struts configuration, using the DelegatingActionProxy class or
+ * the DelegatingRequestProcessor.
+ *
+ *
Note that you can use a single ContextLoaderPlugIn for all Struts modules.
+ * That context can in turn be loaded from multiple XML files, for example split
+ * according to Struts modules. Alternatively, define one ContextLoaderPlugIn per
+ * Struts module, specifying appropriate "contextConfigLocation" parameters.
+ *
+ *
Note: The idea of delegating to Spring-managed Struts Actions originated in
+ * Don Brown's Spring Struts Plugin.
+ * ContextLoaderPlugIn and DelegatingActionProxy constitute a clean-room
+ * implementation of the same idea, essentially superseding the original plugin.
+ * Many thanks to Don Brown and Matt Raible for the original work and for the
+ * agreement to reimplement the idea in Spring proper!
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.1
+ * @see #SERVLET_CONTEXT_PREFIX
+ * @see ActionSupport
+ * @see DispatchActionSupport
+ * @see DelegatingActionProxy
+ * @see DelegatingRequestProcessor
+ * @see DelegatingTilesRequestProcessor
+ * @see org.springframework.web.context.ContextLoaderListener
+ * @see org.springframework.web.context.ContextLoaderServlet
+ * @see org.springframework.web.servlet.FrameworkServlet
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public class ContextLoaderPlugIn implements PlugIn {
+
+ /**
+ * Suffix for WebApplicationContext namespaces. If a Struts ActionServlet is
+ * given the name "action" in a context, the namespace used by this PlugIn will
+ * resolve to "action-servlet".
+ */
+ public static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet";
+
+ /**
+ * Default context class for ContextLoaderPlugIn.
+ * @see org.springframework.web.context.support.XmlWebApplicationContext
+ */
+ public static final Class DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
+
+ /**
+ * Prefix for the ServletContext attribute for the WebApplicationContext.
+ * The completion is the Struts module name.
+ */
+ public static final String SERVLET_CONTEXT_PREFIX = ContextLoaderPlugIn.class.getName() + ".CONTEXT.";
+
+
+ protected final Log logger = LogFactory.getLog(getClass());
+
+ /** Custom WebApplicationContext class */
+ private Class contextClass = DEFAULT_CONTEXT_CLASS;
+
+ /** Namespace for this servlet */
+ private String namespace;
+
+ /** Explicit context config location */
+ private String contextConfigLocation;
+
+ /** The Struts ActionServlet that this PlugIn is registered with */
+ private ActionServlet actionServlet;
+
+ /** The Struts ModuleConfig that this PlugIn is registered with */
+ private ModuleConfig moduleConfig;
+
+ /** WebApplicationContext for the ActionServlet */
+ private WebApplicationContext webApplicationContext;
+
+
+ /**
+ * Set a custom context class by name. This class must be of type WebApplicationContext,
+ * when using the default ContextLoaderPlugIn implementation, the context class
+ * must also implement ConfigurableWebApplicationContext.
+ * @see #createWebApplicationContext
+ */
+ public void setContextClassName(String contextClassName) throws ClassNotFoundException {
+ this.contextClass = ClassUtils.forName(contextClassName);
+ }
+
+ /**
+ * Set a custom context class. This class must be of type WebApplicationContext,
+ * when using the default ContextLoaderPlugIn implementation, the context class
+ * must also implement ConfigurableWebApplicationContext.
+ * @see #createWebApplicationContext
+ */
+ public void setContextClass(Class contextClass) {
+ this.contextClass = contextClass;
+ }
+
+ /**
+ * Return the custom context class.
+ */
+ public Class getContextClass() {
+ return this.contextClass;
+ }
+
+ /**
+ * Set a custom namespace for the ActionServlet,
+ * to be used for building a default context config location.
+ */
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ /**
+ * Return the namespace for the ActionServlet, falling back to default scheme if
+ * no custom namespace was set: e.g. "test-servlet" for a servlet named "test".
+ */
+ public String getNamespace() {
+ if (this.namespace != null) {
+ return this.namespace;
+ }
+ if (this.actionServlet != null) {
+ return this.actionServlet.getServletName() + DEFAULT_NAMESPACE_SUFFIX;
+ }
+ return null;
+ }
+
+ /**
+ * Set the context config location explicitly, instead of relying on the default
+ * location built from the namespace. This location string can consist of
+ * multiple locations separated by any number of commas and spaces.
+ */
+ public void setContextConfigLocation(String contextConfigLocation) {
+ this.contextConfigLocation = contextConfigLocation;
+ }
+
+ /**
+ * Return the explicit context config location, if any.
+ */
+ public String getContextConfigLocation() {
+ return this.contextConfigLocation;
+ }
+
+
+ /**
+ * Create the ActionServlet's WebApplicationContext.
+ */
+ public final void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException {
+ long startTime = System.currentTimeMillis();
+ if (logger.isInfoEnabled()) {
+ logger.info("ContextLoaderPlugIn for Struts ActionServlet '" + actionServlet.getServletName() +
+ ", module '" + moduleConfig.getPrefix() + "': initialization started");
+ }
+
+ this.actionServlet = actionServlet;
+ this.moduleConfig = moduleConfig;
+ try {
+ this.webApplicationContext = initWebApplicationContext();
+ onInit();
+ }
+ catch (RuntimeException ex) {
+ logger.error("Context initialization failed", ex);
+ throw ex;
+ }
+
+ if (logger.isInfoEnabled()) {
+ long elapsedTime = System.currentTimeMillis() - startTime;
+ logger.info("ContextLoaderPlugIn for Struts ActionServlet '" + actionServlet.getServletName() +
+ "', module '" + moduleConfig.getPrefix() + "': initialization completed in " + elapsedTime + " ms");
+ }
+ }
+
+ /**
+ * Return the Struts ActionServlet that this PlugIn is associated with.
+ */
+ public final ActionServlet getActionServlet() {
+ return actionServlet;
+ }
+
+ /**
+ * Return the name of the ActionServlet that this PlugIn is associated with.
+ */
+ public final String getServletName() {
+ return this.actionServlet.getServletName();
+ }
+
+ /**
+ * Return the ServletContext that this PlugIn is associated with.
+ */
+ public final ServletContext getServletContext() {
+ return this.actionServlet.getServletContext();
+ }
+
+ /**
+ * Return the Struts ModuleConfig that this PlugIn is associated with.
+ */
+ public final ModuleConfig getModuleConfig() {
+ return this.moduleConfig;
+ }
+
+ /**
+ * Return the prefix of the ModuleConfig that this PlugIn is associated with.
+ * @see org.apache.struts.config.ModuleConfig#getPrefix
+ */
+ public final String getModulePrefix() {
+ return this.moduleConfig.getPrefix();
+ }
+
+ /**
+ * Initialize and publish the WebApplicationContext for the ActionServlet.
+ *
Delegates to {@link #createWebApplicationContext} for actual creation.
+ *
Can be overridden in subclasses. Call getActionServlet()
+ * and/or getModuleConfig() to access the Struts configuration
+ * that this PlugIn is associated with.
+ * @throws org.springframework.beans.BeansException if the context couldn't be initialized
+ * @throws IllegalStateException if there is already a context for the Struts ActionServlet
+ * @see #getActionServlet()
+ * @see #getServletName()
+ * @see #getServletContext()
+ * @see #getModuleConfig()
+ * @see #getModulePrefix()
+ */
+ protected WebApplicationContext initWebApplicationContext() throws BeansException, IllegalStateException {
+ getServletContext().log("Initializing WebApplicationContext for Struts ActionServlet '" +
+ getServletName() + "', module '" + getModulePrefix() + "'");
+ WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
+
+ WebApplicationContext wac = createWebApplicationContext(parent);
+ if (logger.isInfoEnabled()) {
+ logger.info("Using context class '" + wac.getClass().getName() + "' for servlet '" + getServletName() + "'");
+ }
+
+ // Publish the context as a servlet context attribute.
+ String attrName = getServletContextAttributeName();
+ getServletContext().setAttribute(attrName, wac);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Published WebApplicationContext of Struts ActionServlet '" + getServletName() +
+ "', module '" + getModulePrefix() + "' as ServletContext attribute with name [" + attrName + "]");
+ }
+
+ return wac;
+ }
+
+ /**
+ * Instantiate the WebApplicationContext for the ActionServlet, either a default
+ * XmlWebApplicationContext or a custom context class if set.
+ *
This implementation expects custom contexts to implement ConfigurableWebApplicationContext.
+ * Can be overridden in subclasses.
+ * @throws org.springframework.beans.BeansException if the context couldn't be initialized
+ * @see #setContextClass
+ * @see org.springframework.web.context.support.XmlWebApplicationContext
+ */
+ protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)
+ throws BeansException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("ContextLoaderPlugIn for Struts ActionServlet '" + getServletName() +
+ "', module '" + getModulePrefix() + "' will try to create custom WebApplicationContext " +
+ "context of class '" + getContextClass().getName() + "', using parent context [" + parent + "]");
+ }
+ if (!ConfigurableWebApplicationContext.class.isAssignableFrom(getContextClass())) {
+ throw new ApplicationContextException(
+ "Fatal initialization error in ContextLoaderPlugIn for Struts ActionServlet '" + getServletName() +
+ "', module '" + getModulePrefix() + "': custom WebApplicationContext class [" +
+ getContextClass().getName() + "] is not of type ConfigurableWebApplicationContext");
+ }
+
+ ConfigurableWebApplicationContext wac =
+ (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());
+ wac.setParent(parent);
+ wac.setServletContext(getServletContext());
+ wac.setNamespace(getNamespace());
+ if (getContextConfigLocation() != null) {
+ wac.setConfigLocations(
+ StringUtils.tokenizeToStringArray(
+ getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
+ }
+ wac.addBeanFactoryPostProcessor(
+ new BeanFactoryPostProcessor() {
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
+ beanFactory.addBeanPostProcessor(new ActionServletAwareProcessor(getActionServlet()));
+ beanFactory.ignoreDependencyType(ActionServlet.class);
+ }
+ }
+ );
+
+ wac.refresh();
+ return wac;
+ }
+
+ /**
+ * Return the ServletContext attribute name for this PlugIn's WebApplicationContext.
+ *
The default implementation returns SERVLET_CONTEXT_PREFIX + module prefix.
+ * @see #SERVLET_CONTEXT_PREFIX
+ * @see #getModulePrefix()
+ */
+ public String getServletContextAttributeName() {
+ return SERVLET_CONTEXT_PREFIX + getModulePrefix();
+ }
+
+ /**
+ * Return this PlugIn's WebApplicationContext.
+ */
+ public final WebApplicationContext getWebApplicationContext() {
+ return webApplicationContext;
+ }
+
+ /**
+ * Callback for custom initialization after the context has been set up.
+ * @throws ServletException if initialization failed
+ */
+ protected void onInit() throws ServletException {
+ }
+
+
+ /**
+ * Close the WebApplicationContext of the ActionServlet.
+ * @see org.springframework.context.ConfigurableApplicationContext#close()
+ */
+ public void destroy() {
+ getServletContext().log("Closing WebApplicationContext of Struts ActionServlet '" +
+ getServletName() + "', module '" + getModulePrefix() + "'");
+ if (getWebApplicationContext() instanceof ConfigurableApplicationContext) {
+ ((ConfigurableApplicationContext) getWebApplicationContext()).close();
+ }
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingActionProxy.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingActionProxy.java
new file mode 100644
index 00000000000..7070cf089fd
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingActionProxy.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.config.ModuleConfig;
+
+import org.springframework.beans.BeansException;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * Proxy for a Spring-managed Struts Action that is defined in
+ * {@link ContextLoaderPlugIn ContextLoaderPlugIn's}
+ * {@link WebApplicationContext}.
+ *
+ *
The proxy is defined in the Struts config file, specifying this
+ * class as the action class. This class will delegate to a Struts
+ * Action bean in the ContextLoaderPlugIn context.
+ *
+ *
<action path="/login" type="org.springframework.web.struts.DelegatingActionProxy"/>
+ *
+ * The name of the Action bean in the
+ * WebApplicationContext will be determined from the mapping
+ * path and module prefix. This can be customized by overriding the
+ * determineActionBeanName method.
+ *
+ * Example:
+ *
+ * - mapping path "/login" -> bean name "/login"
+ * - mapping path "/login", module prefix "/mymodule" ->
+ * bean name "/mymodule/login"
+ *
+ *
+ * A corresponding bean definition in the ContextLoaderPlugin
+ * context would look as follows; notice that the Action is now
+ * able to leverage fully Spring's configuration facilities:
+ *
+ *
+ * <bean name="/login" class="myapp.MyAction">
+ * <property name="...">...</property>
+ * </bean>
+ *
+ * Note that you can use a single ContextLoaderPlugIn for all
+ * Struts modules. That context can in turn be loaded from multiple XML files,
+ * for example split according to Struts modules. Alternatively, define one
+ * ContextLoaderPlugIn per Struts module, specifying appropriate
+ * "contextConfigLocation" parameters. In both cases, the Spring bean name
+ * has to include the module prefix.
+ *
+ * If you want to avoid having to specify DelegatingActionProxy
+ * as the Action type in your struts-config file (for example to
+ * be able to generate your Struts config file with XDoclet) consider using the
+ * {@link DelegatingRequestProcessor DelegatingRequestProcessor}.
+ * The latter's disadvantage is that it might conflict with the need
+ * for a different RequestProcessor subclass.
+ *
+ *
The default implementation delegates to the {@link DelegatingActionUtils}
+ * class as much as possible, to reuse as much code as possible with
+ * DelegatingRequestProcessor and
+ * {@link DelegatingTilesRequestProcessor}.
+ *
+ *
Note: The idea of delegating to Spring-managed Struts Actions originated in
+ * Don Brown's Spring Struts Plugin.
+ * ContextLoaderPlugIn and DelegatingActionProxy
+ * constitute a clean-room implementation of the same idea, essentially
+ * superseding the original plugin. Many thanks to Don Brown and Matt Raible
+ * for the original work and for the agreement to reimplement the idea in
+ * Spring proper!
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.1
+ * @see #determineActionBeanName
+ * @see DelegatingRequestProcessor
+ * @see DelegatingTilesRequestProcessor
+ * @see DelegatingActionUtils
+ * @see ContextLoaderPlugIn
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public class DelegatingActionProxy extends Action {
+
+ /**
+ * Pass the execute call on to the Spring-managed delegate Action.
+ * @see #getDelegateAction
+ */
+ @Override
+ public ActionForward execute(
+ ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+
+ Action delegateAction = getDelegateAction(mapping);
+ return delegateAction.execute(mapping, form, request, response);
+ }
+
+
+ /**
+ * Return the delegate Action for the given mapping.
+ *
The default implementation determines a bean name from the
+ * given ActionMapping and looks up the corresponding bean in
+ * the {@link WebApplicationContext}.
+ * @param mapping the Struts ActionMapping
+ * @return the delegate Action
+ * @throws BeansException if thrown by WebApplicationContext methods
+ * @see #determineActionBeanName
+ */
+ protected Action getDelegateAction(ActionMapping mapping) throws BeansException {
+ WebApplicationContext wac = getWebApplicationContext(getServlet(), mapping.getModuleConfig());
+ String beanName = determineActionBeanName(mapping);
+ return (Action) wac.getBean(beanName, Action.class);
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's {@link WebApplicationContext} from the
+ * ServletContext, falling back to the root
+ * WebApplicationContext.
+ *
This context is supposed to contain the Struts Action
+ * beans to delegate to.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see DelegatingActionUtils#findRequiredWebApplicationContext
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ */
+ protected WebApplicationContext getWebApplicationContext(
+ ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
+
+ return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, moduleConfig);
+ }
+
+ /**
+ * Determine the name of the Action bean, to be looked up in
+ * the WebApplicationContext.
+ *
The default implementation takes the
+ * {@link org.apache.struts.action.ActionMapping#getPath mapping path} and
+ * prepends the
+ * {@link org.apache.struts.config.ModuleConfig#getPrefix module prefix},
+ * if any.
+ * @param mapping the Struts ActionMapping
+ * @return the name of the Action bean
+ * @see DelegatingActionUtils#determineActionBeanName
+ * @see org.apache.struts.action.ActionMapping#getPath
+ * @see org.apache.struts.config.ModuleConfig#getPrefix
+ */
+ protected String determineActionBeanName(ActionMapping mapping) {
+ return DelegatingActionUtils.determineActionBeanName(mapping);
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingActionUtils.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingActionUtils.java
new file mode 100644
index 00000000000..0fc85b091f8
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingActionUtils.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2002-2006 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.config.ModuleConfig;
+
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * Common methods for letting Struts Actions work with a
+ * Spring WebApplicationContext.
+ *
+ *
As everything in Struts is based on concrete inheritance,
+ * we have to provide an Action subclass (DelegatingActionProxy) and
+ * two RequestProcessor subclasses (DelegatingRequestProcessor and
+ * DelegatingTilesRequestProcessor). The only way to share common
+ * functionality is a utility class like this one.
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.2
+ * @see DelegatingActionProxy
+ * @see DelegatingRequestProcessor
+ * @see DelegatingTilesRequestProcessor
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public abstract class DelegatingActionUtils {
+
+ /**
+ * The name of the autowire init-param specified on the Struts ActionServlet:
+ * "spring.autowire"
+ */
+ public static final String PARAM_AUTOWIRE = "spring.autowire";
+
+ /**
+ * The name of the dependency check init-param specified on the Struts ActionServlet:
+ * "spring.dependencyCheck"
+ */
+ public static final String PARAM_DEPENDENCY_CHECK = "spring.dependencyCheck";
+
+ /**
+ * Value of the autowire init-param that indicates autowiring by name:
+ * "byName"
+ */
+ public static final String AUTOWIRE_BY_NAME = "byName";
+
+ /**
+ * Value of the autowire init-param that indicates autowiring by type:
+ * "byType"
+ */
+ public static final String AUTOWIRE_BY_TYPE = "byType";
+
+
+ private static final Log logger = LogFactory.getLog(DelegatingActionUtils.class);
+
+
+ /**
+ * Fetch ContextLoaderPlugIn's WebApplicationContext from the ServletContext.
+ *
Checks for a module-specific context first, falling back to the
+ * context for the default module else.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig (can be null)
+ * @return the WebApplicationContext, or null if none
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ */
+ public static WebApplicationContext getWebApplicationContext(
+ ActionServlet actionServlet, ModuleConfig moduleConfig) {
+
+ WebApplicationContext wac = null;
+ String modulePrefix = null;
+
+ // Try module-specific attribute.
+ if (moduleConfig != null) {
+ modulePrefix = moduleConfig.getPrefix();
+ wac = (WebApplicationContext) actionServlet.getServletContext().getAttribute(
+ ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + modulePrefix);
+ }
+
+ // If not found, try attribute for default module.
+ if (wac == null && !"".equals(modulePrefix)) {
+ wac = (WebApplicationContext) actionServlet.getServletContext().getAttribute(
+ ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX);
+ }
+
+ return wac;
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's WebApplicationContext from the ServletContext.
+ *
Checks for a module-specific context first, falling back to the
+ * context for the default module else.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig (can be null)
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ */
+ public static WebApplicationContext getRequiredWebApplicationContext(
+ ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
+
+ WebApplicationContext wac = getWebApplicationContext(actionServlet, moduleConfig);
+ // If no Struts-specific context found, throw an exception.
+ if (wac == null) {
+ throw new IllegalStateException(
+ "Could not find ContextLoaderPlugIn's WebApplicationContext as ServletContext attribute [" +
+ ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + "]: Did you register [" +
+ ContextLoaderPlugIn.class.getName() + "]?");
+ }
+ return wac;
+ }
+
+ /**
+ * Find most specific context available: check ContextLoaderPlugIn's
+ * WebApplicationContext first, fall back to root WebApplicationContext else.
+ *
When checking the ContextLoaderPlugIn context: checks for a module-specific
+ * context first, falling back to the context for the default module else.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig (can be null)
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see #getWebApplicationContext
+ * @see org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContext
+ */
+ public static WebApplicationContext findRequiredWebApplicationContext(
+ ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
+
+ WebApplicationContext wac = getWebApplicationContext(actionServlet, moduleConfig);
+ // If no Struts-specific context found, fall back to root context.
+ if (wac == null) {
+ wac = WebApplicationContextUtils.getRequiredWebApplicationContext(actionServlet.getServletContext());
+ }
+ return wac;
+ }
+
+ /**
+ * Default implementation of Action bean determination, taking
+ * the mapping path and prepending the module prefix, if any.
+ * @param mapping the Struts ActionMapping
+ * @return the name of the Action bean
+ * @see org.apache.struts.action.ActionMapping#getPath
+ * @see org.apache.struts.config.ModuleConfig#getPrefix
+ */
+ public static String determineActionBeanName(ActionMapping mapping) {
+ String prefix = mapping.getModuleConfig().getPrefix();
+ String path = mapping.getPath();
+ String beanName = prefix + path;
+ if (logger.isDebugEnabled()) {
+ logger.debug("DelegatingActionProxy with mapping path '" + path + "' and module prefix '" +
+ prefix + "' delegating to Spring bean with name [" + beanName + "]");
+ }
+ return beanName;
+ }
+
+ /**
+ * Determine the autowire mode from the "autowire" init-param of the
+ * Struts ActionServlet, falling back to "AUTOWIRE_BY_TYPE" as default.
+ * @param actionServlet the Struts ActionServlet
+ * @return the autowire mode to use
+ * @see #PARAM_AUTOWIRE
+ * @see #AUTOWIRE_BY_NAME
+ * @see #AUTOWIRE_BY_TYPE
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBeanProperties
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#AUTOWIRE_BY_TYPE
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#AUTOWIRE_BY_NAME
+ */
+ public static int getAutowireMode(ActionServlet actionServlet) {
+ String autowire = actionServlet.getInitParameter(PARAM_AUTOWIRE);
+ if (autowire != null) {
+ if (AUTOWIRE_BY_NAME.equals(autowire)) {
+ return AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
+ }
+ else if (!AUTOWIRE_BY_TYPE.equals(autowire)) {
+ throw new IllegalArgumentException("ActionServlet 'autowire' parameter must be 'byName' or 'byType'");
+ }
+ }
+ return AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
+ }
+
+ /**
+ * Determine the dependency check to use from the "dependencyCheck" init-param
+ * of the Struts ActionServlet, falling back to no dependency check as default.
+ * @param actionServlet the Struts ActionServlet
+ * @return whether to enforce a dependency check or not
+ * @see #PARAM_DEPENDENCY_CHECK
+ * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#autowireBeanProperties
+ */
+ public static boolean getDependencyCheck(ActionServlet actionServlet) {
+ String dependencyCheck = actionServlet.getInitParameter(PARAM_DEPENDENCY_CHECK);
+ return Boolean.valueOf(dependencyCheck).booleanValue();
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingRequestProcessor.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingRequestProcessor.java
new file mode 100644
index 00000000000..9f8d647b8c6
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingRequestProcessor.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2002-2007 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.action.RequestProcessor;
+import org.apache.struts.config.ModuleConfig;
+
+import org.springframework.beans.BeansException;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * Subclass of Struts's default {@link RequestProcessor} that looks up
+ * Spring-managed Struts {@link Action Actions} defined in
+ * {@link ContextLoaderPlugIn ContextLoaderPlugIn's} {@link WebApplicationContext}
+ * (or, as a fallback, in the root WebApplicationContext).
+ *
+ *
In the Struts config file, you can either specify the original
+ * Action class (as when generated by XDoclet), or no
+ * Action class at all. In any case, Struts will delegate to an
+ * Action bean in the ContextLoaderPlugIn context.
+ *
+ *
<action path="/login" type="myapp.MyAction"/>
+ *
+ * or
+ *
+ * <action path="/login"/>
+ *
+ * The name of the Action bean in the
+ * WebApplicationContext will be determined from the mapping path
+ * and module prefix. This can be customized by overriding the
+ * {@link #determineActionBeanName} method.
+ *
+ * Example:
+ *
+ * - mapping path "/login" -> bean name "/login"
+ * - mapping path "/login", module prefix "/mymodule" ->
+ * bean name "/mymodule/login"
+ *
+ *
+ * A corresponding bean definition in the ContextLoaderPlugin
+ * context would look as follows; notice that the Action is now
+ * able to leverage fully Spring's configuration facilities:
+ *
+ *
+ * <bean name="/login" class="myapp.MyAction">
+ * <property name="...">...</property>
+ * </bean>
+ *
+ * Note that you can use a single ContextLoaderPlugIn for all
+ * Struts modules. That context can in turn be loaded from multiple XML files,
+ * for example split according to Struts modules. Alternatively, define one
+ * ContextLoaderPlugIn per Struts module, specifying appropriate
+ * "contextConfigLocation" parameters. In both cases, the Spring bean name has
+ * to include the module prefix.
+ *
+ * If you also need the Tiles setup functionality of the original
+ * TilesRequestProcessor, use
+ * DelegatingTilesRequestProcessor. As there is just a
+ * single central class to customize in Struts, we have to provide another
+ * subclass here, covering both the Tiles and the Spring delegation aspect.
+ *
+ *
If this RequestProcessor conflicts with the need for a
+ * different RequestProcessor subclass (other than
+ * TilesRequestProcessor), consider using
+ * {@link DelegatingActionProxy} as the Struts Action type in
+ * your struts-config file.
+ *
+ *
The default implementation delegates to the
+ * DelegatingActionUtils class as much as possible, to reuse as
+ * much code as possible despite the need to provide two
+ * RequestProcessor subclasses. If you need to subclass yet
+ * another RequestProcessor, take this class as a template,
+ * delegating to DelegatingActionUtils just like it.
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.2
+ * @see #determineActionBeanName
+ * @see DelegatingTilesRequestProcessor
+ * @see DelegatingActionProxy
+ * @see DelegatingActionUtils
+ * @see ContextLoaderPlugIn
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public class DelegatingRequestProcessor extends RequestProcessor {
+
+ private WebApplicationContext webApplicationContext;
+
+
+ @Override
+ public void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException {
+ super.init(actionServlet, moduleConfig);
+ if (actionServlet != null) {
+ this.webApplicationContext = initWebApplicationContext(actionServlet, moduleConfig);
+ }
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's {@link WebApplicationContext} from the
+ * ServletContext, falling back to the root
+ * WebApplicationContext.
+ *
This context is supposed to contain the Struts Action
+ * beans to delegate to.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see DelegatingActionUtils#findRequiredWebApplicationContext
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ */
+ protected WebApplicationContext initWebApplicationContext(
+ ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
+
+ return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, moduleConfig);
+ }
+
+ /**
+ * Return the WebApplicationContext that this processor
+ * delegates to.
+ */
+ protected final WebApplicationContext getWebApplicationContext() {
+ return this.webApplicationContext;
+ }
+
+
+ /**
+ * Override the base class method to return the delegate action.
+ * @see #getDelegateAction
+ */
+ @Override
+ protected Action processActionCreate(
+ HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
+ throws IOException {
+
+ Action action = getDelegateAction(mapping);
+ if (action != null) {
+ return action;
+ }
+ return super.processActionCreate(request, response, mapping);
+ }
+
+ /**
+ * Return the delegate Action for the given mapping.
+ *
The default implementation determines a bean name from the
+ * given ActionMapping and looks up the corresponding
+ * bean in the WebApplicationContext.
+ * @param mapping the Struts ActionMapping
+ * @return the delegate Action, or null if none found
+ * @throws BeansException if thrown by WebApplicationContext methods
+ * @see #determineActionBeanName
+ */
+ protected Action getDelegateAction(ActionMapping mapping) throws BeansException {
+ String beanName = determineActionBeanName(mapping);
+ if (!getWebApplicationContext().containsBean(beanName)) {
+ return null;
+ }
+ return (Action) getWebApplicationContext().getBean(beanName, Action.class);
+ }
+
+ /**
+ * Determine the name of the Action bean, to be looked up in
+ * the WebApplicationContext.
+ *
The default implementation takes the
+ * {@link org.apache.struts.action.ActionMapping#getPath mapping path} and
+ * prepends the
+ * {@link org.apache.struts.config.ModuleConfig#getPrefix module prefix},
+ * if any.
+ * @param mapping the Struts ActionMapping
+ * @return the name of the Action bean
+ * @see DelegatingActionUtils#determineActionBeanName
+ * @see org.apache.struts.action.ActionMapping#getPath
+ * @see org.apache.struts.config.ModuleConfig#getPrefix
+ */
+ protected String determineActionBeanName(ActionMapping mapping) {
+ return DelegatingActionUtils.determineActionBeanName(mapping);
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingTilesRequestProcessor.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingTilesRequestProcessor.java
new file mode 100644
index 00000000000..9749ad53b01
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DelegatingTilesRequestProcessor.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2002-2006 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.config.ModuleConfig;
+import org.apache.struts.tiles.TilesRequestProcessor;
+
+import org.springframework.beans.BeansException;
+import org.springframework.web.context.WebApplicationContext;
+
+/**
+ * Subclass of Struts's TilesRequestProcessor that autowires
+ * Struts Actions defined in ContextLoaderPlugIn's WebApplicationContext
+ * (or, as a fallback, in the root WebApplicationContext).
+ *
+ *
Behaves like
+ * {@link DelegatingRequestProcessor DelegatingRequestProcessor},
+ * but also provides the Tiles functionality of the original TilesRequestProcessor.
+ * As there's just a single central class to customize in Struts, we have to provide
+ * another subclass here, covering both the Tiles and the Spring delegation aspect.
+ *
+ *
The default implementation delegates to the DelegatingActionUtils
+ * class as fas as possible, to reuse as much code as possible despite
+ * the need to provide two RequestProcessor subclasses. If you need to
+ * subclass yet another RequestProcessor, take this class as a template,
+ * delegating to DelegatingActionUtils just like it.
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.2
+ * @see DelegatingRequestProcessor
+ * @see DelegatingActionProxy
+ * @see DelegatingActionUtils
+ * @see ContextLoaderPlugIn
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public class DelegatingTilesRequestProcessor extends TilesRequestProcessor {
+
+ private WebApplicationContext webApplicationContext;
+
+
+ @Override
+ public void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException {
+ super.init(actionServlet, moduleConfig);
+ if (actionServlet != null) {
+ this.webApplicationContext = initWebApplicationContext(actionServlet, moduleConfig);
+ }
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's WebApplicationContext from the ServletContext,
+ * falling back to the root WebApplicationContext. This context is supposed
+ * to contain the Struts Action beans to delegate to.
+ * @param actionServlet the associated ActionServlet
+ * @param moduleConfig the associated ModuleConfig
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see DelegatingActionUtils#findRequiredWebApplicationContext
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ */
+ protected WebApplicationContext initWebApplicationContext(
+ ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
+
+ return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, moduleConfig);
+ }
+
+ /**
+ * Return the WebApplicationContext that this processor delegates to.
+ */
+ protected final WebApplicationContext getWebApplicationContext() {
+ return webApplicationContext;
+ }
+
+
+ /**
+ * Override the base class method to return the delegate action.
+ * @see #getDelegateAction
+ */
+ @Override
+ protected Action processActionCreate(
+ HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
+ throws IOException {
+
+ Action action = getDelegateAction(mapping);
+ if (action != null) {
+ return action;
+ }
+ return super.processActionCreate(request, response, mapping);
+ }
+
+ /**
+ * Return the delegate Action for the given mapping.
+ *
The default implementation determines a bean name from the
+ * given ActionMapping and looks up the corresponding bean in the
+ * WebApplicationContext.
+ * @param mapping the Struts ActionMapping
+ * @return the delegate Action, or null if none found
+ * @throws BeansException if thrown by WebApplicationContext methods
+ * @see #determineActionBeanName
+ */
+ protected Action getDelegateAction(ActionMapping mapping) throws BeansException {
+ String beanName = determineActionBeanName(mapping);
+ if (!getWebApplicationContext().containsBean(beanName)) {
+ return null;
+ }
+ return (Action) getWebApplicationContext().getBean(beanName, Action.class);
+ }
+
+ /**
+ * Determine the name of the Action bean, to be looked up in
+ * the WebApplicationContext.
+ *
The default implementation takes the mapping path and
+ * prepends the module prefix, if any.
+ * @param mapping the Struts ActionMapping
+ * @return the name of the Action bean
+ * @see DelegatingActionUtils#determineActionBeanName
+ * @see ActionMapping#getPath
+ * @see ModuleConfig#getPrefix
+ */
+ protected String determineActionBeanName(ActionMapping mapping) {
+ return DelegatingActionUtils.determineActionBeanName(mapping);
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DispatchActionSupport.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DispatchActionSupport.java
new file mode 100644
index 00000000000..bb74fafa1c9
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/DispatchActionSupport.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2002-2005 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.io.File;
+
+import javax.servlet.ServletContext;
+
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.actions.DispatchAction;
+
+import org.springframework.context.support.MessageSourceAccessor;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.util.WebUtils;
+
+/**
+ * Convenience class for Spring-aware Struts 1.1+ DispatchActions.
+ *
+ *
Provides a reference to the current Spring application context, e.g.
+ * for bean lookup or resource loading. Auto-detects a ContextLoaderPlugIn
+ * context, falling back to the root WebApplicationContext. For typical
+ * usage, i.e. accessing middle tier beans, use a root WebApplicationContext.
+ *
+ *
For classic Struts Actions or Lookup/MappingDispatchActions, use the
+ * analogous {@link ActionSupport ActionSupport} or
+ * {@link LookupDispatchActionSupport LookupDispatchActionSupport} /
+ * {@link MappingDispatchActionSupport MappingDispatchActionSupport} class,
+ * respectively.
+ *
+ *
As an alternative approach, you can wire your Struts Actions themselves
+ * as Spring beans, passing references to them via IoC rather than looking
+ * up references in a programmatic fashion. Check out
+ * {@link DelegatingActionProxy DelegatingActionProxy} and
+ * {@link DelegatingRequestProcessor DelegatingRequestProcessor}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.0.1
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ * @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
+ * @see org.springframework.web.context.ContextLoaderListener
+ * @see org.springframework.web.context.ContextLoaderServlet
+ * @see ActionSupport
+ * @see LookupDispatchActionSupport
+ * @see MappingDispatchActionSupport
+ * @see DelegatingActionProxy
+ * @see DelegatingRequestProcessor
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public abstract class DispatchActionSupport extends DispatchAction {
+
+ private WebApplicationContext webApplicationContext;
+
+ private MessageSourceAccessor messageSourceAccessor;
+
+
+ /**
+ * Initialize the WebApplicationContext for this Action.
+ * Invokes onInit after successful initialization of the context.
+ * @see #initWebApplicationContext
+ * @see #onInit
+ */
+ @Override
+ public void setServlet(ActionServlet actionServlet) {
+ super.setServlet(actionServlet);
+ if (actionServlet != null) {
+ this.webApplicationContext = initWebApplicationContext(actionServlet);
+ this.messageSourceAccessor = new MessageSourceAccessor(this.webApplicationContext);
+ onInit();
+ }
+ else {
+ onDestroy();
+ }
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's WebApplicationContext from the ServletContext,
+ * falling back to the root WebApplicationContext (the usual case).
+ * @param actionServlet the associated ActionServlet
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see DelegatingActionUtils#findRequiredWebApplicationContext
+ */
+ protected WebApplicationContext initWebApplicationContext(ActionServlet actionServlet)
+ throws IllegalStateException {
+
+ return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, null);
+ }
+
+
+ /**
+ * Return the current Spring WebApplicationContext.
+ */
+ protected final WebApplicationContext getWebApplicationContext() {
+ return this.webApplicationContext;
+ }
+
+ /**
+ * Return a MessageSourceAccessor for the application context
+ * used by this object, for easy message access.
+ */
+ protected final MessageSourceAccessor getMessageSourceAccessor() {
+ return this.messageSourceAccessor;
+ }
+
+ /**
+ * Return the current ServletContext.
+ */
+ protected final ServletContext getServletContext() {
+ return this.webApplicationContext.getServletContext();
+ }
+
+ /**
+ * Return the temporary directory for the current web application,
+ * as provided by the servlet container.
+ * @return the File representing the temporary directory
+ */
+ protected final File getTempDir() {
+ return WebUtils.getTempDir(getServletContext());
+ }
+
+
+ /**
+ * Callback for custom initialization after the context has been set up.
+ * @see #setServlet
+ */
+ protected void onInit() {
+ }
+
+ /**
+ * Callback for custom destruction when the ActionServlet shuts down.
+ * @see #setServlet
+ */
+ protected void onDestroy() {
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/LookupDispatchActionSupport.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/LookupDispatchActionSupport.java
new file mode 100644
index 00000000000..9c606b91b34
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/LookupDispatchActionSupport.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2002-2005 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.io.File;
+
+import javax.servlet.ServletContext;
+
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.actions.LookupDispatchAction;
+
+import org.springframework.context.support.MessageSourceAccessor;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.util.WebUtils;
+
+/**
+ * Convenience class for Spring-aware Struts 1.1+ LookupDispatchActions.
+ *
+ *
Provides a reference to the current Spring application context, e.g.
+ * for bean lookup or resource loading. Auto-detects a ContextLoaderPlugIn
+ * context, falling back to the root WebApplicationContext. For typical
+ * usage, i.e. accessing middle tier beans, use a root WebApplicationContext.
+ *
+ *
For classic Struts Actions, DispatchActions or MappingDispatchActions,
+ * use the analogous {@link ActionSupport ActionSupport} or
+ * {@link DispatchActionSupport DispatchActionSupport} /
+ * {@link MappingDispatchActionSupport MappingDispatchActionSupport} class.
+ *
+ *
As an alternative approach, you can wire your Struts Actions themselves
+ * as Spring beans, passing references to them via IoC rather than looking
+ * up references in a programmatic fashion. Check out
+ * {@link DelegatingActionProxy DelegatingActionProxy} and
+ * {@link DelegatingRequestProcessor DelegatingRequestProcessor}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ * @see WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
+ * @see org.springframework.web.context.ContextLoaderListener
+ * @see org.springframework.web.context.ContextLoaderServlet
+ * @see ActionSupport
+ * @see DispatchActionSupport
+ * @see MappingDispatchActionSupport
+ * @see DelegatingActionProxy
+ * @see DelegatingRequestProcessor
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public abstract class LookupDispatchActionSupport extends LookupDispatchAction {
+
+ private WebApplicationContext webApplicationContext;
+
+ private MessageSourceAccessor messageSourceAccessor;
+
+
+ /**
+ * Initialize the WebApplicationContext for this Action.
+ * Invokes onInit after successful initialization of the context.
+ * @see #initWebApplicationContext
+ * @see #onInit
+ */
+ @Override
+ public void setServlet(ActionServlet actionServlet) {
+ super.setServlet(actionServlet);
+ if (actionServlet != null) {
+ this.webApplicationContext = initWebApplicationContext(actionServlet);
+ this.messageSourceAccessor = new MessageSourceAccessor(this.webApplicationContext);
+ onInit();
+ }
+ else {
+ onDestroy();
+ }
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's WebApplicationContext from the ServletContext,
+ * falling back to the root WebApplicationContext (the usual case).
+ * @param actionServlet the associated ActionServlet
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see DelegatingActionUtils#findRequiredWebApplicationContext
+ */
+ protected WebApplicationContext initWebApplicationContext(ActionServlet actionServlet)
+ throws IllegalStateException {
+
+ return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, null);
+ }
+
+
+ /**
+ * Return the current Spring WebApplicationContext.
+ */
+ protected final WebApplicationContext getWebApplicationContext() {
+ return this.webApplicationContext;
+ }
+
+ /**
+ * Return a MessageSourceAccessor for the application context
+ * used by this object, for easy message access.
+ */
+ protected final MessageSourceAccessor getMessageSourceAccessor() {
+ return this.messageSourceAccessor;
+ }
+
+ /**
+ * Return the current ServletContext.
+ */
+ protected final ServletContext getServletContext() {
+ return this.webApplicationContext.getServletContext();
+ }
+
+ /**
+ * Return the temporary directory for the current web application,
+ * as provided by the servlet container.
+ * @return the File representing the temporary directory
+ */
+ protected final File getTempDir() {
+ return WebUtils.getTempDir(getServletContext());
+ }
+
+
+ /**
+ * Callback for custom initialization after the context has been set up.
+ * @see #setServlet
+ */
+ protected void onInit() {
+ }
+
+ /**
+ * Callback for custom destruction when the ActionServlet shuts down.
+ * @see #setServlet
+ */
+ protected void onDestroy() {
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/MappingDispatchActionSupport.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/MappingDispatchActionSupport.java
new file mode 100644
index 00000000000..ec08c10771c
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/MappingDispatchActionSupport.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2002-2005 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.io.File;
+
+import javax.servlet.ServletContext;
+
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.actions.MappingDispatchAction;
+
+import org.springframework.context.support.MessageSourceAccessor;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.util.WebUtils;
+
+/**
+ * Convenience class for Spring-aware Struts 1.2 MappingDispatchActions.
+ *
+ *
Provides a reference to the current Spring application context, e.g.
+ * for bean lookup or resource loading. Auto-detects a ContextLoaderPlugIn
+ * context, falling back to the root WebApplicationContext. For typical
+ * usage, i.e. accessing middle tier beans, use a root WebApplicationContext.
+ *
+ *
For classic Struts Actions, DispatchActions or LookupDispatchActions,
+ * use the analogous {@link ActionSupport ActionSupport} or
+ * {@link DispatchActionSupport DispatchActionSupport} /
+ * {@link LookupDispatchActionSupport LookupDispatchActionSupport} class.
+ *
+ *
As an alternative approach, you can wire your Struts Actions themselves
+ * as Spring beans, passing references to them via IoC rather than looking
+ * up references in a programmatic fashion. Check out
+ * {@link DelegatingActionProxy DelegatingActionProxy} and
+ * {@link DelegatingRequestProcessor DelegatingRequestProcessor}.
+ *
+ * @author Juergen Hoeller
+ * @since 1.1.3
+ * @see ContextLoaderPlugIn#SERVLET_CONTEXT_PREFIX
+ * @see WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
+ * @see org.springframework.web.context.ContextLoaderListener
+ * @see org.springframework.web.context.ContextLoaderServlet
+ * @see ActionSupport
+ * @see DispatchActionSupport
+ * @see LookupDispatchActionSupport
+ * @see DelegatingActionProxy
+ * @see DelegatingRequestProcessor
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public abstract class MappingDispatchActionSupport extends MappingDispatchAction {
+
+ private WebApplicationContext webApplicationContext;
+
+ private MessageSourceAccessor messageSourceAccessor;
+
+
+ /**
+ * Initialize the WebApplicationContext for this Action.
+ * Invokes onInit after successful initialization of the context.
+ * @see #initWebApplicationContext
+ * @see #onInit
+ */
+ @Override
+ public void setServlet(ActionServlet actionServlet) {
+ super.setServlet(actionServlet);
+ if (actionServlet != null) {
+ this.webApplicationContext = initWebApplicationContext(actionServlet);
+ this.messageSourceAccessor = new MessageSourceAccessor(this.webApplicationContext);
+ onInit();
+ }
+ else {
+ onDestroy();
+ }
+ }
+
+ /**
+ * Fetch ContextLoaderPlugIn's WebApplicationContext from the ServletContext,
+ * falling back to the root WebApplicationContext (the usual case).
+ * @param actionServlet the associated ActionServlet
+ * @return the WebApplicationContext
+ * @throws IllegalStateException if no WebApplicationContext could be found
+ * @see DelegatingActionUtils#findRequiredWebApplicationContext
+ */
+ protected WebApplicationContext initWebApplicationContext(ActionServlet actionServlet)
+ throws IllegalStateException {
+
+ return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, null);
+ }
+
+
+ /**
+ * Return the current Spring WebApplicationContext.
+ */
+ protected final WebApplicationContext getWebApplicationContext() {
+ return this.webApplicationContext;
+ }
+
+ /**
+ * Return a MessageSourceAccessor for the application context
+ * used by this object, for easy message access.
+ */
+ protected final MessageSourceAccessor getMessageSourceAccessor() {
+ return this.messageSourceAccessor;
+ }
+
+ /**
+ * Return the current ServletContext.
+ */
+ protected final ServletContext getServletContext() {
+ return this.webApplicationContext.getServletContext();
+ }
+
+ /**
+ * Return the temporary directory for the current web application,
+ * as provided by the servlet container.
+ * @return the File representing the temporary directory
+ */
+ protected final File getTempDir() {
+ return WebUtils.getTempDir(getServletContext());
+ }
+
+
+ /**
+ * Callback for custom initialization after the context has been set up.
+ * @see #setServlet
+ */
+ protected void onInit() {
+ }
+
+ /**
+ * Callback for custom destruction when the ActionServlet shuts down.
+ * @see #setServlet
+ */
+ protected void onDestroy() {
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/SpringBindingActionForm.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/SpringBindingActionForm.java
new file mode 100644
index 00000000000..c16f719c626
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/SpringBindingActionForm.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2002-2006 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Iterator;
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.beanutils.BeanUtilsBean;
+import org.apache.commons.beanutils.ConvertUtilsBean;
+import org.apache.commons.beanutils.PropertyUtilsBean;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.Globals;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionMessage;
+import org.apache.struts.action.ActionMessages;
+import org.apache.struts.util.MessageResources;
+
+import org.springframework.context.MessageSourceResolvable;
+import org.springframework.validation.Errors;
+import org.springframework.validation.FieldError;
+import org.springframework.validation.ObjectError;
+
+/**
+ * A thin Struts ActionForm adapter that delegates to Spring's more complete
+ * and advanced data binder and Errors object underneath the covers to bind
+ * to POJOs and manage rejected values.
+ *
+ *
Exposes Spring-managed errors to the standard Struts view tags, through
+ * exposing a corresponding Struts ActionMessages object as request attribute.
+ * Also exposes current field values in a Struts-compliant fashion, including
+ * rejected values (which Spring's binding keeps even for non-String fields).
+ *
+ *
Consequently, Struts views can be written in a completely traditional
+ * fashion (with standard html:form, html:errors, etc),
+ * seamlessly accessing a Spring-bound POJO form object underneath.
+ *
+ *
Note this ActionForm is designed explicitly for use in request scope.
+ * It expects to receive an expose call from the Action, passing
+ * in the Errors object to expose plus the current HttpServletRequest.
+ *
+ *
Example definition in struts-config.xml:
+ *
+ *
+ * <form-beans>
+ * <form-bean name="actionForm" type="org.springframework.web.struts.SpringBindingActionForm"/>
+ * </form-beans>
+ *
+ * Example code in a custom Struts Action:
+ *
+ *
+ * public ActionForward execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws Exception {
+ * SpringBindingActionForm form = (SpringBindingActionForm) actionForm;
+ * MyPojoBean bean = ...;
+ * ServletRequestDataBinder binder = new ServletRequestDataBinder(bean, "myPojo");
+ * binder.bind(request);
+ * form.expose(binder.getBindingResult(), request);
+ * return actionMapping.findForward("success");
+ * }
+ *
+ * This class is compatible with both Struts 1.2.x and Struts 1.1.
+ * On Struts 1.2, default messages registered with Spring binding errors
+ * are exposed when none of the error codes could be resolved.
+ * On Struts 1.1, this is not possible due to a limitation in the Struts
+ * message facility; hence, we expose the plain default error code there.
+ *
+ * @author Keith Donald
+ * @author Juergen Hoeller
+ * @since 1.2.2
+ * @see #expose(org.springframework.validation.Errors, javax.servlet.http.HttpServletRequest)
+ * @deprecated as of Spring 3.0
+ */
+@Deprecated
+public class SpringBindingActionForm extends ActionForm {
+
+ private static final Log logger = LogFactory.getLog(SpringBindingActionForm.class);
+
+ private static boolean defaultActionMessageAvailable = true;
+
+
+ static {
+ // Register special PropertyUtilsBean subclass that knows how to
+ // extract field values from a SpringBindingActionForm.
+ // As a consequence of the static nature of Commons BeanUtils,
+ // we have to resort to this initialization hack here.
+ ConvertUtilsBean convUtils = new ConvertUtilsBean();
+ PropertyUtilsBean propUtils = new SpringBindingAwarePropertyUtilsBean();
+ BeanUtilsBean beanUtils = new BeanUtilsBean(convUtils, propUtils);
+ BeanUtilsBean.setInstance(beanUtils);
+
+ // Determine whether the Struts 1.2 support for default messages
+ // is available on ActionMessage: ActionMessage(String, boolean)
+ // with "false" to be passed into the boolean flag.
+ try {
+ ActionMessage.class.getConstructor(new Class[] {String.class, boolean.class});
+ }
+ catch (NoSuchMethodException ex) {
+ defaultActionMessageAvailable = false;
+ }
+ }
+
+
+ private Errors errors;
+
+ private Locale locale;
+
+ private MessageResources messageResources;
+
+
+ /**
+ * Set the Errors object that this SpringBindingActionForm is supposed
+ * to wrap. The contained field values and errors will be exposed
+ * to the view, accessible through Struts standard tags.
+ * @param errors the Spring Errors object to wrap, usually taken from
+ * a DataBinder that has been used for populating a POJO form object
+ * @param request the HttpServletRequest to retrieve the attributes from
+ * @see org.springframework.validation.DataBinder#getBindingResult()
+ */
+ public void expose(Errors errors, HttpServletRequest request) {
+ this.errors = errors;
+
+ // Obtain the locale from Struts well-known location.
+ this.locale = (Locale) request.getSession().getAttribute(Globals.LOCALE_KEY);
+
+ // Obtain the MessageResources from Struts' well-known location.
+ this.messageResources = (MessageResources) request.getAttribute(Globals.MESSAGES_KEY);
+
+ if (errors != null && errors.hasErrors()) {
+ // Add global ActionError instances from the Spring Errors object.
+ ActionMessages actionMessages = (ActionMessages) request.getAttribute(Globals.ERROR_KEY);
+ if (actionMessages == null) {
+ request.setAttribute(Globals.ERROR_KEY, getActionMessages());
+ }
+ else {
+ actionMessages.add(getActionMessages());
+ }
+ }
+ }
+
+
+ /**
+ * Return an ActionMessages representation of this SpringBindingActionForm,
+ * exposing all errors contained in the underlying Spring Errors object.
+ * @see org.springframework.validation.Errors#getAllErrors()
+ */
+ private ActionMessages getActionMessages() {
+ ActionMessages actionMessages = new ActionMessages();
+ Iterator it = this.errors.getAllErrors().iterator();
+ while (it.hasNext()) {
+ ObjectError objectError = (ObjectError) it.next();
+ String effectiveMessageKey = findEffectiveMessageKey(objectError);
+ if (effectiveMessageKey == null && !defaultActionMessageAvailable) {
+ // Need to specify default code despite it not being resolvable:
+ // Struts 1.1 ActionMessage doesn't support default messages.
+ effectiveMessageKey = objectError.getCode();
+ }
+ ActionMessage message = (effectiveMessageKey != null) ?
+ new ActionMessage(effectiveMessageKey, resolveArguments(objectError.getArguments())) :
+ new ActionMessage(objectError.getDefaultMessage(), false);
+ if (objectError instanceof FieldError) {
+ FieldError fieldError = (FieldError) objectError;
+ actionMessages.add(fieldError.getField(), message);
+ }
+ else {
+ actionMessages.add(ActionMessages.GLOBAL_MESSAGE, message);
+ }
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Final ActionMessages used for binding: " + actionMessages);
+ }
+ return actionMessages;
+ }
+
+ private Object[] resolveArguments(Object[] arguments) {
+ if (arguments == null || arguments.length == 0) {
+ return arguments;
+ }
+ for (int i = 0; i < arguments.length; i++) {
+ Object arg = arguments[i];
+ if (arg instanceof MessageSourceResolvable) {
+ MessageSourceResolvable resolvable = (MessageSourceResolvable)arg;
+ String[] codes = resolvable.getCodes();
+ boolean resolved = false;
+ if (this.messageResources != null) {
+ for (int j = 0; j < codes.length; j++) {
+ String code = codes[j];
+ if (this.messageResources.isPresent(this.locale, code)) {
+ arguments[i] = this.messageResources.getMessage(
+ this.locale, code, resolveArguments(resolvable.getArguments()));
+ resolved = true;
+ break;
+ }
+ }
+ }
+ if (!resolved) {
+ arguments[i] = resolvable.getDefaultMessage();
+ }
+ }
+ }
+ return arguments;
+ }
+
+ /**
+ * Find the most specific message key for the given error.
+ * @param error the ObjectError to find a message key for
+ * @return the most specific message key found
+ */
+ private String findEffectiveMessageKey(ObjectError error) {
+ if (this.messageResources != null) {
+ String[] possibleMatches = error.getCodes();
+ for (int i = 0; i < possibleMatches.length; i++) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Looking for error code '" + possibleMatches[i] + "'");
+ }
+ if (this.messageResources.isPresent(this.locale, possibleMatches[i])) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found error code '" + possibleMatches[i] + "' in resource bundle");
+ }
+ return possibleMatches[i];
+ }
+ }
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Could not find a suitable message error code, returning default message");
+ }
+ return null;
+ }
+
+
+ /**
+ * Get the formatted value for the property at the provided path.
+ * The formatted value is a string value for display, converted
+ * via a registered property editor.
+ * @param propertyPath the property path
+ * @return the formatted property value
+ * @throws NoSuchMethodException if called during Struts binding
+ * (without Spring Errors object being exposed), to indicate no
+ * available property to Struts
+ */
+ private Object getFieldValue(String propertyPath) throws NoSuchMethodException {
+ if (this.errors == null) {
+ throw new NoSuchMethodException(
+ "No bean properties exposed to Struts binding - performing Spring binding later on");
+ }
+ return this.errors.getFieldValue(propertyPath);
+ }
+
+
+ /**
+ * Special subclass of PropertyUtilsBean that it is aware of SpringBindingActionForm
+ * and uses it for retrieving field values. The field values will be taken from
+ * the underlying POJO form object that the Spring Errors object was created for.
+ */
+ private static class SpringBindingAwarePropertyUtilsBean extends PropertyUtilsBean {
+
+ @Override
+ public Object getNestedProperty(Object bean, String propertyPath)
+ throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+
+ // Extract Spring-managed field value in case of SpringBindingActionForm.
+ if (bean instanceof SpringBindingActionForm) {
+ SpringBindingActionForm form = (SpringBindingActionForm) bean;
+ return form.getFieldValue(propertyPath);
+ }
+
+ // Else fall back to default PropertyUtils behavior.
+ return super.getNestedProperty(bean, propertyPath);
+ }
+ }
+
+}
diff --git a/org.springframework.web.struts/src/main/java/org/springframework/web/struts/package-info.java b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/package-info.java
new file mode 100644
index 00000000000..b299f31263d
--- /dev/null
+++ b/org.springframework.web.struts/src/main/java/org/springframework/web/struts/package-info.java
@@ -0,0 +1,28 @@
+/**
+ * Support classes for integrating a Struts web tier with a Spring middle
+ * tier which is typically hosted in a Spring root WebApplicationContext.
+ *
+ * Supports easy access to the Spring root WebApplicationContext
+ * from Struts Actions via the ActionSupport and DispatchActionSupport
+ * classes. Actions have full access to Spring's WebApplicationContext
+ * facilities in this case, and explicitly look up Spring-managed beans.
+ *
+ *
Also supports wiring Struts Actions as Spring-managed beans in
+ * a ContextLoaderPlugIn context, passing middle tier references to them
+ * via bean references, using the Action path as bean name. There are two
+ * ways to make Struts delegate Action lookup to the ContextLoaderPlugIn:
+ *
+ *
+ * - Use DelegationActionProxy as Action "type" in struts-config.
+ * There's no further setup necessary; you can choose any RequestProcessor.
+ * Each such proxy will automatically delegate to the corresponding
+ * Spring-managed Action bean in the ContextLoaderPlugIn context.
+ *
+ *
- Configure DelegatingRequestProcessor as "processorClass" in
+ * struts-config, using the original Action "type" (possibly generated
+ * by XDoclet) or no "type" at all. To also use Tiles, configure
+ * DelegatingTilesRequestProcessor instead.
+ *
+ */
+@Deprecated
+package org.springframework.web.struts;
\ No newline at end of file
diff --git a/org.springframework.web.struts/src/test/java/org/springframework/web/servlet/view/tiles/TestComponentController.java b/org.springframework.web.struts/src/test/java/org/springframework/web/servlet/view/tiles/TestComponentController.java
new file mode 100644
index 00000000000..d65b6c7a4dc
--- /dev/null
+++ b/org.springframework.web.struts/src/test/java/org/springframework/web/servlet/view/tiles/TestComponentController.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2002-2005 the original author or authors.
+ *
+ * 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.springframework.web.servlet.view.tiles;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts.tiles.ComponentContext;
+
+/**
+ * @author Juergen Hoeller
+ * @since 22.08.2003
+ */
+public class TestComponentController extends ComponentControllerSupport {
+
+ @Override
+ protected void doPerform(ComponentContext componentContext, HttpServletRequest request, HttpServletResponse response) {
+ request.setAttribute("testAttr", "testVal");
+ TilesView.setPath(request, "/WEB-INF/jsp/layout.jsp");
+ }
+
+}
diff --git a/org.springframework.web.struts/src/test/java/org/springframework/web/servlet/view/tiles/TilesViewTests.java b/org.springframework.web.struts/src/test/java/org/springframework/web/servlet/view/tiles/TilesViewTests.java
new file mode 100644
index 00000000000..389c18f9b37
--- /dev/null
+++ b/org.springframework.web.struts/src/test/java/org/springframework/web/servlet/view/tiles/TilesViewTests.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2002-2008 the original author or authors.
+ *
+ * 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.springframework.web.servlet.view.tiles;
+
+import java.util.HashMap;
+import java.util.Locale;
+import javax.servlet.jsp.jstl.core.Config;
+import javax.servlet.jsp.jstl.fmt.LocalizationContext;
+
+import org.apache.struts.taglib.tiles.ComponentConstants;
+import org.apache.struts.tiles.ComponentContext;
+import org.apache.struts.tiles.PathAttribute;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.StaticWebApplicationContext;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
+import org.springframework.web.servlet.i18n.FixedLocaleResolver;
+import org.springframework.web.servlet.view.InternalResourceViewResolver;
+
+/**
+ * @author Alef Arendsen
+ * @author Juergen Hoeller
+ */
+public class TilesViewTests {
+
+ protected StaticWebApplicationContext prepareWebApplicationContext() throws Exception {
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ MockServletContext sc = new MockServletContext("/org/springframework/web/servlet/view/tiles/");
+ wac.setServletContext(sc);
+ wac.refresh();
+
+ TilesConfigurer tc = new TilesConfigurer();
+ tc.setDefinitions(new String[] {"tiles-test.xml"});
+ tc.setValidateDefinitions(true);
+ tc.setApplicationContext(wac);
+ tc.afterPropertiesSet();
+
+ return wac;
+ }
+
+ @Test
+ public void tilesView() throws Exception {
+ WebApplicationContext wac = prepareWebApplicationContext();
+
+ InternalResourceViewResolver irvr = new InternalResourceViewResolver();
+ irvr.setApplicationContext(wac);
+ irvr.setViewClass(TilesView.class);
+ View view = irvr.resolveViewName("testTile", new Locale("nl", ""));
+
+ MockHttpServletRequest request = new MockHttpServletRequest(wac.getServletContext());
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
+ request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new AcceptHeaderLocaleResolver());
+
+ view.render(new HashMap(), request, response);
+ assertEquals("/WEB-INF/jsp/layout.jsp", response.getForwardedUrl());
+ ComponentContext cc = (ComponentContext) request.getAttribute(ComponentConstants.COMPONENT_CONTEXT);
+ assertNotNull(cc);
+ PathAttribute attr = (PathAttribute) cc.getAttribute("content");
+ assertEquals("/WEB-INF/jsp/content.jsp", attr.getValue());
+
+ view.render(new HashMap(), request, response);
+ assertEquals("/WEB-INF/jsp/layout.jsp", response.getForwardedUrl());
+ cc = (ComponentContext) request.getAttribute(ComponentConstants.COMPONENT_CONTEXT);
+ assertNotNull(cc);
+ attr = (PathAttribute) cc.getAttribute("content");
+ assertEquals("/WEB-INF/jsp/content.jsp", attr.getValue());
+ }
+
+ @Test
+ public void tilesJstlView() throws Exception {
+ Locale locale = !Locale.GERMAN.equals(Locale.getDefault()) ? Locale.GERMAN : Locale.FRENCH;
+
+ StaticWebApplicationContext wac = prepareWebApplicationContext();
+
+ InternalResourceViewResolver irvr = new InternalResourceViewResolver();
+ irvr.setApplicationContext(wac);
+ irvr.setViewClass(TilesJstlView.class);
+ View view = irvr.resolveViewName("testTile", new Locale("nl", ""));
+
+ MockHttpServletRequest request = new MockHttpServletRequest(wac.getServletContext());
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
+ request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new FixedLocaleResolver(locale));
+ wac.addMessage("code1", locale, "messageX");
+ view.render(new HashMap(), request, response);
+
+ assertEquals("/WEB-INF/jsp/layout.jsp", response.getForwardedUrl());
+ ComponentContext cc = (ComponentContext) request.getAttribute(ComponentConstants.COMPONENT_CONTEXT);
+ assertNotNull(cc);
+ PathAttribute attr = (PathAttribute) cc.getAttribute("content");
+ assertEquals("/WEB-INF/jsp/content.jsp", attr.getValue());
+
+ assertEquals(locale, Config.get(request, Config.FMT_LOCALE));
+ LocalizationContext lc = (LocalizationContext) Config.get(request, Config.FMT_LOCALIZATION_CONTEXT);
+ assertEquals("messageX", lc.getResourceBundle().getString("code1"));
+ }
+
+ @Test
+ public void tilesJstlViewWithContextParam() throws Exception {
+ Locale locale = !Locale.GERMAN.equals(Locale.getDefault()) ? Locale.GERMAN : Locale.FRENCH;
+
+ StaticWebApplicationContext wac = prepareWebApplicationContext();
+ ((MockServletContext) wac.getServletContext()).addInitParameter(
+ Config.FMT_LOCALIZATION_CONTEXT, "org/springframework/web/servlet/view/tiles/context-messages");
+
+ InternalResourceViewResolver irvr = new InternalResourceViewResolver();
+ irvr.setApplicationContext(wac);
+ irvr.setViewClass(TilesJstlView.class);
+ View view = irvr.resolveViewName("testTile", new Locale("nl", ""));
+
+ MockHttpServletRequest request = new MockHttpServletRequest(wac.getServletContext());
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ wac.addMessage("code1", locale, "messageX");
+ request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
+ request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new FixedLocaleResolver(locale));
+
+ view.render(new HashMap(), request, response);
+ assertEquals("/WEB-INF/jsp/layout.jsp", response.getForwardedUrl());
+ ComponentContext cc = (ComponentContext) request.getAttribute(ComponentConstants.COMPONENT_CONTEXT);
+ assertNotNull(cc);
+ PathAttribute attr = (PathAttribute) cc.getAttribute("content");
+ assertEquals("/WEB-INF/jsp/content.jsp", attr.getValue());
+
+ LocalizationContext lc = (LocalizationContext) Config.get(request, Config.FMT_LOCALIZATION_CONTEXT);
+ assertEquals("message1", lc.getResourceBundle().getString("code1"));
+ assertEquals("message2", lc.getResourceBundle().getString("code2"));
+ }
+
+ @Test
+ public void tilesViewWithController() throws Exception {
+ WebApplicationContext wac = prepareWebApplicationContext();
+
+ InternalResourceViewResolver irvr = new InternalResourceViewResolver();
+ irvr.setApplicationContext(wac);
+ irvr.setViewClass(TilesView.class);
+ View view = irvr.resolveViewName("testTileWithController", new Locale("nl", ""));
+
+ MockHttpServletRequest request = new MockHttpServletRequest(wac.getServletContext());
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
+ request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new AcceptHeaderLocaleResolver());
+ view.render(new HashMap(), request, response);
+ assertEquals("/WEB-INF/jsp/layout.jsp", response.getForwardedUrl());
+ ComponentContext cc = (ComponentContext) request.getAttribute(ComponentConstants.COMPONENT_CONTEXT);
+ assertNotNull(cc);
+ PathAttribute attr = (PathAttribute) cc.getAttribute("content");
+ assertEquals("/WEB-INF/jsp/otherContent.jsp", attr.getValue());
+ assertEquals("testVal", request.getAttribute("testAttr"));
+
+ view.render(new HashMap(), request, response);
+ assertEquals("/WEB-INF/jsp/layout.jsp", response.getForwardedUrl());
+ cc = (ComponentContext) request.getAttribute(ComponentConstants.COMPONENT_CONTEXT);
+ assertNotNull(cc);
+ attr = (PathAttribute) cc.getAttribute("content");
+ assertEquals("/WEB-INF/jsp/otherContent.jsp", attr.getValue());
+ assertEquals("testVal", request.getAttribute("testAttr"));
+ }
+
+}
diff --git a/org.springframework.web.struts/src/test/java/org/springframework/web/struts/StrutsSupportTests.java b/org.springframework.web.struts/src/test/java/org/springframework/web/struts/StrutsSupportTests.java
new file mode 100644
index 00000000000..93394707022
--- /dev/null
+++ b/org.springframework.web.struts/src/test/java/org/springframework/web/struts/StrutsSupportTests.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2002-2005 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.config.ModuleConfig;
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.StaticWebApplicationContext;
+
+/**
+ * @author Juergen Hoeller
+ * @since 09.04.2004
+ */
+public class StrutsSupportTests {
+
+ @Test
+ public void actionSupportWithContextLoaderPlugIn() throws ServletException {
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.addMessage("test", Locale.getDefault(), "testmessage");
+ final ServletContext servletContext = new MockServletContext();
+ wac.setServletContext(servletContext);
+ wac.refresh();
+ servletContext.setAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX, wac);
+
+ ActionServlet actionServlet = new ActionServlet() {
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+ };
+ ActionSupport action = new ActionSupport() {
+ };
+ action.setServlet(actionServlet);
+
+ assertEquals(wac, action.getWebApplicationContext());
+ assertEquals(servletContext, action.getServletContext());
+ assertEquals("testmessage", action.getMessageSourceAccessor().getMessage("test"));
+
+ action.setServlet(null);
+ }
+
+ @Test
+ public void actionSupportWithRootContext() throws ServletException {
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.addMessage("test", Locale.getDefault(), "testmessage");
+ final ServletContext servletContext = new MockServletContext();
+ wac.setServletContext(servletContext);
+ wac.refresh();
+ servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
+
+ ActionServlet actionServlet = new ActionServlet() {
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+ };
+ ActionSupport action = new ActionSupport() {
+ };
+ action.setServlet(actionServlet);
+
+ assertEquals(wac, action.getWebApplicationContext());
+ assertEquals(servletContext, action.getServletContext());
+ assertEquals("testmessage", action.getMessageSourceAccessor().getMessage("test"));
+
+ action.setServlet(null);
+ }
+
+ @Test
+ public void dispatchActionSupportWithContextLoaderPlugIn() throws ServletException {
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.addMessage("test", Locale.getDefault(), "testmessage");
+ final ServletContext servletContext = new MockServletContext();
+ wac.setServletContext(servletContext);
+ wac.refresh();
+ servletContext.setAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX, wac);
+
+ ActionServlet actionServlet = new ActionServlet() {
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+ };
+ DispatchActionSupport action = new DispatchActionSupport() {
+ };
+ action.setServlet(actionServlet);
+
+ assertEquals(wac, action.getWebApplicationContext());
+ assertEquals(servletContext, action.getServletContext());
+ assertEquals("testmessage", action.getMessageSourceAccessor().getMessage("test"));
+
+ action.setServlet(null);
+ }
+
+ @Test
+ public void dispatchActionSupportWithRootContext() throws ServletException {
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.addMessage("test", Locale.getDefault(), "testmessage");
+ final ServletContext servletContext = new MockServletContext();
+ wac.setServletContext(servletContext);
+ wac.refresh();
+ servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
+
+ ActionServlet actionServlet = new ActionServlet() {
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+ };
+ DispatchActionSupport action = new DispatchActionSupport() {
+ };
+ action.setServlet(actionServlet);
+
+ assertEquals(wac, action.getWebApplicationContext());
+ assertEquals(servletContext, action.getServletContext());
+ assertEquals("testmessage", action.getMessageSourceAccessor().getMessage("test"));
+
+ action.setServlet(null);
+ }
+
+ @Test
+ public void lookupDispatchActionSupportWithContextLoaderPlugIn() throws ServletException {
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.addMessage("test", Locale.getDefault(), "testmessage");
+ final ServletContext servletContext = new MockServletContext();
+ wac.setServletContext(servletContext);
+ wac.refresh();
+ servletContext.setAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX, wac);
+
+ ActionServlet actionServlet = new ActionServlet() {
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+ };
+ LookupDispatchActionSupport action = new LookupDispatchActionSupport() {
+ @Override
+ protected Map getKeyMethodMap() {
+ return new HashMap();
+ }
+ };
+ action.setServlet(actionServlet);
+
+ assertEquals(wac, action.getWebApplicationContext());
+ assertEquals(servletContext, action.getServletContext());
+ assertEquals("testmessage", action.getMessageSourceAccessor().getMessage("test"));
+
+ action.setServlet(null);
+ }
+
+ @Test
+ public void lookupDispatchActionSupportWithRootContext() throws ServletException {
+ StaticWebApplicationContext wac = new StaticWebApplicationContext();
+ wac.addMessage("test", Locale.getDefault(), "testmessage");
+ final ServletContext servletContext = new MockServletContext();
+ wac.setServletContext(servletContext);
+ wac.refresh();
+ servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
+
+ ActionServlet actionServlet = new ActionServlet() {
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+ };
+ LookupDispatchActionSupport action = new LookupDispatchActionSupport() {
+ @Override
+ protected Map getKeyMethodMap() {
+ return new HashMap();
+ }
+ };
+ action.setServlet(actionServlet);
+
+ assertEquals(wac, action.getWebApplicationContext());
+ assertEquals(servletContext, action.getServletContext());
+ assertEquals("testmessage", action.getMessageSourceAccessor().getMessage("test"));
+
+ action.setServlet(null);
+ }
+
+ @Test
+ public void testDelegatingActionProxy() throws Exception {
+ final MockServletContext servletContext = new MockServletContext("/org/springframework/web/struts/");
+ ContextLoaderPlugIn plugin = new ContextLoaderPlugIn();
+ ActionServlet actionServlet = new ActionServlet() {
+ @Override
+ public String getServletName() {
+ return "action";
+ }
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+ };
+
+ ModuleConfig moduleConfig = createMock(ModuleConfig.class);
+ expect(moduleConfig.getPrefix()).andReturn("").anyTimes();
+ replay(moduleConfig);
+
+ plugin.init(actionServlet, moduleConfig);
+ assertTrue(servletContext.getAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX) != null);
+
+ DelegatingActionProxy proxy = new DelegatingActionProxy();
+ proxy.setServlet(actionServlet);
+ ActionMapping mapping = new ActionMapping();
+ mapping.setPath("/test");
+ mapping.setModuleConfig(moduleConfig);
+ ActionForward forward = proxy.execute(
+ mapping, null, new MockHttpServletRequest(servletContext), new MockHttpServletResponse());
+ assertEquals("/test", forward.getPath());
+
+ TestAction testAction = (TestAction) plugin.getWebApplicationContext().getBean("/test");
+ assertTrue(testAction.getServlet() != null);
+ proxy.setServlet(null);
+ plugin.destroy();
+ assertTrue(testAction.getServlet() == null);
+
+ verify(moduleConfig);
+ }
+
+ @Test
+ public void delegatingActionProxyWithModule() throws Exception {
+ final MockServletContext servletContext = new MockServletContext("/org/springframework/web/struts/WEB-INF");
+ ContextLoaderPlugIn plugin = new ContextLoaderPlugIn();
+ plugin.setContextConfigLocation("action-servlet.xml");
+ ActionServlet actionServlet = new ActionServlet() {
+ @Override
+ public String getServletName() {
+ return "action";
+ }
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+ };
+
+ ModuleConfig moduleConfig = createMock(ModuleConfig.class);
+ expect(moduleConfig.getPrefix()).andReturn("/module").anyTimes();
+ replay(moduleConfig);
+
+ plugin.init(actionServlet, moduleConfig);
+ assertTrue(servletContext.getAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX) == null);
+ assertTrue(servletContext.getAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + "/module") != null);
+
+ DelegatingActionProxy proxy = new DelegatingActionProxy();
+ proxy.setServlet(actionServlet);
+ ActionMapping mapping = new ActionMapping();
+ mapping.setPath("/test2");
+ mapping.setModuleConfig(moduleConfig);
+ ActionForward forward = proxy.execute(
+ mapping, null, new MockHttpServletRequest(servletContext), new MockHttpServletResponse());
+ assertEquals("/module/test2", forward.getPath());
+
+ TestAction testAction = (TestAction) plugin.getWebApplicationContext().getBean("/module/test2");
+ assertTrue(testAction.getServlet() != null);
+ proxy.setServlet(null);
+ plugin.destroy();
+ assertTrue(testAction.getServlet() == null);
+
+ verify(moduleConfig);
+ }
+
+ @Test
+ public void delegatingActionProxyWithModuleAndDefaultContext() throws Exception {
+ final MockServletContext servletContext = new MockServletContext("/org/springframework/web/struts/WEB-INF");
+ ContextLoaderPlugIn plugin = new ContextLoaderPlugIn();
+ plugin.setContextConfigLocation("action-servlet.xml");
+ ActionServlet actionServlet = new ActionServlet() {
+ @Override
+ public String getServletName() {
+ return "action";
+ }
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+ };
+
+ ModuleConfig defaultModuleConfig = createMock(ModuleConfig.class);
+ expect(defaultModuleConfig.getPrefix()).andReturn("").anyTimes();
+
+ ModuleConfig moduleConfig = createMock(ModuleConfig.class);
+ expect(moduleConfig.getPrefix()).andReturn("/module").anyTimes();
+
+ replay(defaultModuleConfig, moduleConfig);
+
+ plugin.init(actionServlet, defaultModuleConfig);
+ assertTrue(servletContext.getAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX) != null);
+ assertTrue(servletContext.getAttribute(ContextLoaderPlugIn.SERVLET_CONTEXT_PREFIX + "/module") == null);
+
+ DelegatingActionProxy proxy = new DelegatingActionProxy();
+ proxy.setServlet(actionServlet);
+ ActionMapping mapping = new ActionMapping();
+ mapping.setPath("/test2");
+ mapping.setModuleConfig(moduleConfig);
+ ActionForward forward = proxy.execute(
+ mapping, null, new MockHttpServletRequest(servletContext), new MockHttpServletResponse());
+ assertEquals("/module/test2", forward.getPath());
+
+ TestAction testAction = (TestAction) plugin.getWebApplicationContext().getBean("/module/test2");
+ assertTrue(testAction.getServlet() != null);
+ proxy.setServlet(null);
+ plugin.destroy();
+ assertTrue(testAction.getServlet() == null);
+
+ verify(defaultModuleConfig, moduleConfig);
+ }
+
+}
diff --git a/org.springframework.web.struts/src/test/java/org/springframework/web/struts/TestAction.java b/org.springframework.web.struts/src/test/java/org/springframework/web/struts/TestAction.java
new file mode 100644
index 00000000000..68dda908f51
--- /dev/null
+++ b/org.springframework.web.struts/src/test/java/org/springframework/web/struts/TestAction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2002-2006 the original author or authors.
+ *
+ * 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.springframework.web.struts;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.struts.action.Action;
+import org.apache.struts.action.ActionForm;
+import org.apache.struts.action.ActionForward;
+import org.apache.struts.action.ActionMapping;
+
+import org.springframework.beans.factory.BeanNameAware;
+
+/**
+ * @author Juergen Hoeller
+ * @since 09.04.2004
+ */
+public class TestAction extends Action implements BeanNameAware {
+
+ private String beanName;
+
+ public void setBeanName(String beanName) {
+ this.beanName = beanName;
+ }
+
+ @Override
+ public ActionForward execute(
+ ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response){
+
+ return new ActionForward(this.beanName);
+ }
+
+}
diff --git a/org.springframework.web.struts/src/test/resources/log4j.xml b/org.springframework.web.struts/src/test/resources/log4j.xml
new file mode 100644
index 00000000000..767b96d6206
--- /dev/null
+++ b/org.springframework.web.struts/src/test/resources/log4j.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/context-messages.properties b/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/context-messages.properties
new file mode 100644
index 00000000000..57aa4782a7b
--- /dev/null
+++ b/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/context-messages.properties
@@ -0,0 +1,6 @@
+code1=message1
+code2=message2
+
+# Example taken from the javadocs for the java.text.MessageFormat class
+message.format.example1=At '{1,time}' on "{1,date}", there was "{2}" on planet {0,number,integer}.
+message.format.example2=This is a test message in the message catalog with no args.
diff --git a/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/context-messages_en_GB.properties b/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/context-messages_en_GB.properties
new file mode 100644
index 00000000000..623a71a8401
--- /dev/null
+++ b/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/context-messages_en_GB.properties
@@ -0,0 +1,2 @@
+# Example taken from the javadocs for the java.text.MessageFormat class
+message.format.example1=At '{1,time}' on "{1,date}", there was "{2}" on station number {0,number,integer}.
\ No newline at end of file
diff --git a/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/context-messages_en_US.properties b/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/context-messages_en_US.properties
new file mode 100644
index 00000000000..2bdc0944860
--- /dev/null
+++ b/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/context-messages_en_US.properties
@@ -0,0 +1,5 @@
+code1=message1
+
+# Example taken from the javadocs for the java.text.MessageFormat class
+message.format.example1=At '{1,time}' on "{1,date}", there was "{2}" on planet {0,number,integer}.
+message.format.example2=This is a test message in the message catalog with no args.
\ No newline at end of file
diff --git a/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/tiles-test.xml b/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/tiles-test.xml
new file mode 100644
index 00000000000..27b48515116
--- /dev/null
+++ b/org.springframework.web.struts/src/test/resources/org/springframework/web/servlet/view/tiles/tiles-test.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/org.springframework.web.struts/src/test/resources/org/springframework/web/struts/WEB-INF/action-servlet.xml b/org.springframework.web.struts/src/test/resources/org/springframework/web/struts/WEB-INF/action-servlet.xml
new file mode 100644
index 00000000000..f934cc1f1ca
--- /dev/null
+++ b/org.springframework.web.struts/src/test/resources/org/springframework/web/struts/WEB-INF/action-servlet.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/org.springframework.web.struts/template.mf b/org.springframework.web.struts/template.mf
new file mode 100644
index 00000000000..98f01a26f55
--- /dev/null
+++ b/org.springframework.web.struts/template.mf
@@ -0,0 +1,19 @@
+Bundle-SymbolicName: org.springframework.web.struts
+Bundle-Name: Spring Web Struts
+Bundle-Vendor: SpringSource
+Bundle-ManifestVersion: 2
+Import-Template:
+ javax.servlet.*;version="[2.4.0, 3.0.0)",
+ org.apache.commons.beanutils.*;version="[1.7.0, 2.0.0)",
+ org.apache.commons.logging.*;version="[1.0.4, 2.0.0)",
+ org.apache.struts.*;version="[1.2.9, 2.0.0)",
+ org.springframework.beans.*;version="[3.0.0, 3.0.1)",
+ org.springframework.context.*;version="[3.0.0, 3.0.1)",
+ org.springframework.util.*;version="[3.0.0, 3.0.1)",
+ org.springframework.validation.*;version="[3.0.0, 3.0.1)",
+ org.springframework.web.*;version="[3.0.0, 3.0.1)"
+Ignored-Existing-Headers:
+ Bnd-LastModified,
+ Import-Package,
+ Export-Package,
+ Tool
diff --git a/org.springframework.web.struts/web-struts.iml b/org.springframework.web.struts/web-struts.iml
new file mode 100644
index 00000000000..c7f4b4aac98
--- /dev/null
+++ b/org.springframework.web.struts/web-struts.iml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+