KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > struts > ContextLoaderPlugIn


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.web.struts;
18
19 import javax.servlet.ServletContext JavaDoc;
20 import javax.servlet.ServletException JavaDoc;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.struts.action.ActionServlet;
25 import org.apache.struts.action.PlugIn;
26 import org.apache.struts.config.ModuleConfig;
27
28 import org.springframework.beans.BeanUtils;
29 import org.springframework.beans.BeansException;
30 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
31 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
32 import org.springframework.context.ApplicationContextException;
33 import org.springframework.context.ConfigurableApplicationContext;
34 import org.springframework.util.ClassUtils;
35 import org.springframework.util.StringUtils;
36 import org.springframework.web.context.ConfigurableWebApplicationContext;
37 import org.springframework.web.context.WebApplicationContext;
38 import org.springframework.web.context.support.WebApplicationContextUtils;
39 import org.springframework.web.context.support.XmlWebApplicationContext;
40
41 /**
42  * Struts 1.1+ PlugIn that loads a Spring application context for the Struts
43  * ActionServlet. This context will automatically refer to the root
44  * WebApplicationContext (loaded by ContextLoaderListener/Servlet) as parent.
45  *
46  * <p>The default namespace of the WebApplicationContext is the name of the
47  * Struts ActionServlet, suffixed with "-servlet" (e.g. "action-servlet").
48  * The default location of the XmlWebApplicationContext configuration file
49  * is therefore "/WEB-INF/action-servlet.xml".
50  *
51  * <pre>
52  * &lt;plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"/&gt;</pre>
53  *
54  * The location of the context configuration files can be customized
55  * through the "contextConfigLocation" setting, analogous to the root
56  * WebApplicationContext and FrameworkServlet contexts.
57  *
58  * <pre>
59  * &lt;plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"&gt;
60  * &lt;set-property property="contextConfigLocation" value="/WEB-INF/action-servlet.xml /WEB-INF/myContext.xml"/&gt;
61  * &lt;/plug-in&gt;</pre>
62  *
63  * Beans defined in the ContextLoaderPlugIn context can be accessed
64  * from conventional Struts Actions, via fetching the WebApplicationContext
65  * reference from the ServletContext. ActionSupport and DispatchActionSupport
66  * are pre-built convenience classes that provide easy access to the context.
67  *
68  * <p>It is normally preferable to access Spring's root WebApplicationContext
69  * in such scenarios, though: A shared middle tier should be defined there
70  * rather than in a ContextLoaderPlugin context, for access by any web component.
71  * ActionSupport and DispatchActionSupport autodetect the root context too.
72  *
73  * <p>A special usage of this PlugIn is to define Struts Actions themselves
74  * as beans, typically wiring them with middle tier components defined in the
75  * root context. Such Actions will then be delegated to by proxy definitions
76  * in the Struts configuration, using the DelegatingActionProxy class or
77  * the DelegatingRequestProcessor.
78  *
79  * <p>Note that you can use a single ContextLoaderPlugIn for all Struts modules.
80  * That context can in turn be loaded from multiple XML files, for example split
81  * according to Struts modules. Alternatively, define one ContextLoaderPlugIn per
82  * Struts module, specifying appropriate "contextConfigLocation" parameters.
83  *
84  * <p>Note: The idea of delegating to Spring-managed Struts Actions originated in
85  * Don Brown's <a HREF="http://struts.sourceforge.net/struts-spring">Spring Struts Plugin</a>.
86  * ContextLoaderPlugIn and DelegatingActionProxy constitute a clean-room
87  * implementation of the same idea, essentially superseding the original plugin.
88  * Many thanks to Don Brown and Matt Raible for the original work and for the
89  * agreement to reimplement the idea in Spring proper!
90  *
91  * @author Juergen Hoeller
92  * @since 1.0.1
93  * @see #SERVLET_CONTEXT_PREFIX
94  * @see ActionSupport
95  * @see DispatchActionSupport
96  * @see DelegatingActionProxy
97  * @see DelegatingRequestProcessor
98  * @see DelegatingTilesRequestProcessor
99  * @see org.springframework.web.context.ContextLoaderListener
100  * @see org.springframework.web.context.ContextLoaderServlet
101  * @see org.springframework.web.servlet.FrameworkServlet
102  */

103 public class ContextLoaderPlugIn implements PlugIn {
104
105     /**
106      * Suffix for WebApplicationContext namespaces. If a Struts ActionServlet is
107      * given the name "action" in a context, the namespace used by this PlugIn will
108      * resolve to "action-servlet".
109      */

110     public static final String JavaDoc DEFAULT_NAMESPACE_SUFFIX = "-servlet";
111
112     /**
113      * Default context class for ContextLoaderPlugIn.
114      * @see org.springframework.web.context.support.XmlWebApplicationContext
115      */

116     public static final Class JavaDoc DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
117
118     /**
119      * Prefix for the ServletContext attribute for the WebApplicationContext.
120      * The completion is the Struts module name.
121      */

122     public static final String JavaDoc SERVLET_CONTEXT_PREFIX = ContextLoaderPlugIn.class.getName() + ".CONTEXT.";
123
124
125     protected final Log logger = LogFactory.getLog(getClass());
126
127     /** Custom WebApplicationContext class */
128     private Class JavaDoc contextClass = DEFAULT_CONTEXT_CLASS;
129
130     /** Namespace for this servlet */
131     private String JavaDoc namespace;
132
133     /** Explicit context config location */
134     private String JavaDoc contextConfigLocation;
135
136     /** The Struts ActionServlet that this PlugIn is registered with */
137     private ActionServlet actionServlet;
138
139     /** The Struts ModuleConfig that this PlugIn is registered with */
140     private ModuleConfig moduleConfig;
141
142     /** WebApplicationContext for the ActionServlet */
143     private WebApplicationContext webApplicationContext;
144
145
146     /**
147      * Set a custom context class by name. This class must be of type WebApplicationContext,
148      * when using the default ContextLoaderPlugIn implementation, the context class
149      * must also implement ConfigurableWebApplicationContext.
150      * @see #createWebApplicationContext
151      */

152     public void setContextClassName(String JavaDoc contextClassName) throws ClassNotFoundException JavaDoc {
153         this.contextClass = ClassUtils.forName(contextClassName);
154     }
155
156     /**
157      * Set a custom context class. This class must be of type WebApplicationContext,
158      * when using the default ContextLoaderPlugIn implementation, the context class
159      * must also implement ConfigurableWebApplicationContext.
160      * @see #createWebApplicationContext
161      */

162     public void setContextClass(Class JavaDoc contextClass) {
163         this.contextClass = contextClass;
164     }
165
166     /**
167      * Return the custom context class.
168      */

169     public Class JavaDoc getContextClass() {
170         return contextClass;
171     }
172
173     /**
174      * Set a custom namespace for the ActionServlet,
175      * to be used for building a default context config location.
176      */

177     public void setNamespace(String JavaDoc namespace) {
178         this.namespace = namespace;
179     }
180
181     /**
182      * Return the namespace for the ActionServlet, falling back to default scheme if
183      * no custom namespace was set: e.g. "test-servlet" for a servlet named "test".
184      */

185     public String JavaDoc getNamespace() {
186         if (this.namespace != null) {
187             return this.namespace;
188         }
189         if (this.actionServlet != null) {
190             return this.actionServlet.getServletName() + DEFAULT_NAMESPACE_SUFFIX;
191         }
192         return null;
193     }
194
195     /**
196      * Set the context config location explicitly, instead of relying on the default
197      * location built from the namespace. This location string can consist of
198      * multiple locations separated by any number of commas and spaces.
199      */

200     public void setContextConfigLocation(String JavaDoc contextConfigLocation) {
201         this.contextConfigLocation = contextConfigLocation;
202     }
203
204     /**
205      * Return the explicit context config location, if any.
206      */

207     public String JavaDoc getContextConfigLocation() {
208         return contextConfigLocation;
209     }
210
211
212     /**
213      * Create the ActionServlet's WebApplicationContext.
214      */

215     public final void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException JavaDoc {
216         long startTime = System.currentTimeMillis();
217         if (logger.isInfoEnabled()) {
218             logger.info("ContextLoaderPlugIn for Struts ActionServlet '" + actionServlet.getServletName() +
219                     ", module '" + moduleConfig.getPrefix() + "': initialization started");
220         }
221
222         this.actionServlet = actionServlet;
223         this.moduleConfig = moduleConfig;
224         try {
225             this.webApplicationContext = initWebApplicationContext();
226             onInit();
227         }
228         catch (RuntimeException JavaDoc ex) {
229             logger.error("Context initialization failed", ex);
230             throw ex;
231         }
232
233         if (logger.isInfoEnabled()) {
234             long elapsedTime = System.currentTimeMillis() - startTime;
235             logger.info("ContextLoaderPlugIn for Struts ActionServlet '" + actionServlet.getServletName() +
236                     "', module '" + moduleConfig.getPrefix() + "': initialization completed in " + elapsedTime + " ms");
237         }
238     }
239
240     /**
241      * Return the Struts ActionServlet that this PlugIn is associated with.
242      */

243     public final ActionServlet getActionServlet() {
244         return actionServlet;
245     }
246
247     /**
248      * Return the name of the ActionServlet that this PlugIn is associated with.
249      */

250     public final String JavaDoc getServletName() {
251         return this.actionServlet.getServletName();
252     }
253
254     /**
255      * Return the ServletContext that this PlugIn is associated with.
256      */

257     public final ServletContext JavaDoc getServletContext() {
258         return this.actionServlet.getServletContext();
259     }
260
261     /**
262      * Return the Struts ModuleConfig that this PlugIn is associated with.
263      */

264     public final ModuleConfig getModuleConfig() {
265         return moduleConfig;
266     }
267
268     /**
269      * Return the prefix of the ModuleConfig that this PlugIn is associated with.
270      * @see org.apache.struts.config.ModuleConfig#getPrefix
271      */

272     public final String JavaDoc getModulePrefix() {
273         return this.moduleConfig.getPrefix();
274     }
275
276     /**
277      * Initialize and publish the WebApplicationContext for the ActionServlet.
278      * Delegates to createWebApplicationContext for actual creation.
279      * <p>Can be overridden in subclasses. Call <code>getActionServlet</code>
280      * and/or <code>getModuleConfig</code> to access the Struts configuration
281      * that this PlugIn is associated with.
282      * @throws org.springframework.beans.BeansException if the context couldn't be initialized
283      * @throws IllegalStateException if there is already a context for the Struts ActionServlet
284      * @see #createWebApplicationContext
285      * @see #getActionServlet
286      * @see #getServletName
287      * @see #getServletContext
288      * @see #getModuleConfig
289      * @see #getModulePrefix
290      */

291     protected WebApplicationContext initWebApplicationContext() throws BeansException, IllegalStateException JavaDoc {
292         getServletContext().log("Initializing WebApplicationContext for Struts ActionServlet '" +
293                 getServletName() + "', module '" + getModulePrefix() + "'");
294         WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
295
296         WebApplicationContext wac = createWebApplicationContext(parent);
297         if (logger.isInfoEnabled()) {
298             logger.info("Using context class '" + wac.getClass().getName() + "' for servlet '" + getServletName() + "'");
299         }
300
301         // Publish the context as a servlet context attribute.
302
String JavaDoc attrName = getServletContextAttributeName();
303         getServletContext().setAttribute(attrName, wac);
304         if (logger.isDebugEnabled()) {
305             logger.debug("Published WebApplicationContext of Struts ActionServlet '" + getServletName() +
306                     "', module '" + getModulePrefix() + "' as ServletContext attribute with name [" + attrName + "]");
307         }
308         
309         return wac;
310     }
311
312     /**
313      * Instantiate the WebApplicationContext for the ActionServlet, either a default
314      * XmlWebApplicationContext or a custom context class if set. This implementation
315      * expects custom contexts to implement ConfigurableWebApplicationContext.
316      * Can be overridden in subclasses.
317      * @throws org.springframework.beans.BeansException if the context couldn't be initialized
318      * @see #setContextClass
319      * @see org.springframework.web.context.support.XmlWebApplicationContext
320      */

321     protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)
322             throws BeansException {
323
324         if (logger.isDebugEnabled()) {
325             logger.debug("ContextLoaderPlugIn for Struts ActionServlet '" + getServletName() +
326                     "', module '" + getModulePrefix() + "' will try to create custom WebApplicationContext " +
327                     "context of class '" + getContextClass().getName() + "', using parent context [" + parent + "]");
328         }
329         if (!ConfigurableWebApplicationContext.class.isAssignableFrom(getContextClass())) {
330             throw new ApplicationContextException(
331                     "Fatal initialization error in ContextLoaderPlugIn for Struts ActionServlet '" + getServletName() +
332                     "', module '" + getModulePrefix() + "': custom WebApplicationContext class [" +
333                     getContextClass().getName() + "] is not of type ConfigurableWebApplicationContext");
334         }
335
336         ConfigurableWebApplicationContext wac =
337                 (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());
338         wac.setParent(parent);
339         wac.setServletContext(getServletContext());
340         wac.setNamespace(getNamespace());
341         if (getContextConfigLocation() != null) {
342             wac.setConfigLocations(
343                 StringUtils.tokenizeToStringArray(
344                             getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
345         }
346         wac.addBeanFactoryPostProcessor(
347                 new BeanFactoryPostProcessor() {
348                     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
349                         beanFactory.addBeanPostProcessor(new ActionServletAwareProcessor(getActionServlet()));
350                         beanFactory.ignoreDependencyType(ActionServlet.class);
351                     }
352                 }
353         );
354
355         wac.refresh();
356         return wac;
357     }
358
359     /**
360      * Return the ServletContext attribute name for this PlugIn's WebApplicationContext.
361      * Default implementation returns SERVLET_CONTEXT_PREFIX + module prefix.
362      * @see #SERVLET_CONTEXT_PREFIX
363      * @see #getModulePrefix
364      */

365     public String JavaDoc getServletContextAttributeName() {
366         return SERVLET_CONTEXT_PREFIX + getModulePrefix();
367     }
368
369     /**
370      * Return this PlugIn's WebApplicationContext.
371      */

372     public final WebApplicationContext getWebApplicationContext() {
373         return webApplicationContext;
374     }
375
376     /**
377      * Callback for custom initialization after the context has been set up.
378      * @throws ServletException if initialization failed
379      */

380     protected void onInit() throws ServletException JavaDoc {
381     }
382
383
384     /**
385      * Close the WebApplicationContext of the ActionServlet.
386      * @see org.springframework.context.ConfigurableApplicationContext#close
387      */

388     public void destroy() {
389         getServletContext().log("Closing WebApplicationContext of Struts ActionServlet '" +
390                 getServletName() + "', module '" + getModulePrefix() + "'");
391         if (getWebApplicationContext() instanceof ConfigurableApplicationContext) {
392             ((ConfigurableApplicationContext) getWebApplicationContext()).close();
393         }
394     }
395
396 }
397
Popular Tags