001: /*
002: * Copyright 2002-2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.web.servlet.mvc;
018:
019: import java.util.Enumeration;
020: import java.util.Properties;
021:
022: import javax.servlet.Servlet;
023: import javax.servlet.ServletConfig;
024: import javax.servlet.ServletContext;
025: import javax.servlet.http.HttpServletRequest;
026: import javax.servlet.http.HttpServletResponse;
027:
028: import org.springframework.beans.factory.BeanNameAware;
029: import org.springframework.beans.factory.DisposableBean;
030: import org.springframework.beans.factory.InitializingBean;
031: import org.springframework.web.servlet.ModelAndView;
032:
033: /**
034: * Spring Controller implementation that wraps a servlet instance which it manages
035: * internally. Such a wrapped servlet is not known outside of this controller;
036: * its entire lifecycle is covered here (in contrast to ServletForwardingController).
037: *
038: * <p>Useful to invoke an existing servlet via Spring's dispatching infrastructure,
039: * for example to apply Spring HandlerInterceptors to its requests. This will work
040: * even in a Servlet 2.2 container that does not support Servlet filters.
041: *
042: * <p>In particular, the main intent of this controller is to allow for applying
043: * Spring's OpenSessionInViewInterceptor or OpenPersistenceManagerInViewInterceptor
044: * to Struts actions in a Servlet 2.2 container. The Struts ActionServlet will be
045: * wrapped by this controller in such a scenario, rather than defined in web.xml.
046: * You then need to map "/*.do" (or whatever pattern you choose for your Struts actions)
047: * onto this controller, which will in turn forward to the Struts ActionServlet.
048: *
049: * <p>Note that Struts has a special requirement in that it parses web.xml to
050: * find its servlet mapping. Therefore, you need to specify the DispatcherServlet's
051: * servlet name as "servletName" on this controller, so that Struts finds the
052: * DispatcherServlet's mapping (thinking that it refers to the ActionServlet).
053: *
054: * <p>In a Servlet 2.3 container, when not using Spring's own web MVC framework,
055: * it is recommended to use classic servlet mapping in combination with a filter,
056: * for example Spring's OpenSessionInViewFilter or OpenPersistenceManagerInViewFilter.
057: *
058: * <p><b>Example:</b> a DispatcherServlet XML context, forwarding "*.do" to the Struts
059: * ActionServlet wrapped by a ServletWrappingController. All such requests will go
060: * through the configured HandlerInterceptor chain (e.g. an OpenSessionInViewInterceptor).
061: * From the Struts point of view, everything will work as usual.
062: *
063: * <pre>
064: * <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
065: * <property name="interceptors">
066: * <list>
067: * <ref bean="openSessionInViewInterceptor"/>
068: * </list>
069: * </property>
070: * <property name="mappings">
071: * <props>
072: * <prop key="*.do">strutsWrappingController</prop>
073: * </props>
074: * </property>
075: * </bean>
076: *
077: * <bean id="strutsWrappingController" class="org.springframework.web.servlet.mvc.ServletWrappingController">
078: * <property name="servletClass">
079: * <value>org.apache.struts.action.ActionServlet</value>
080: * </property>
081: * <property name="servletName">
082: * <value>action</value>
083: * </property>
084: * <property name="initParameters">
085: * <props>
086: * <prop key="config">/WEB-INF/struts-config.xml</prop>
087: * </props>
088: * </property>
089: * </bean></pre>
090: *
091: * Thanks to Keith Garry Boyce for pointing out the issue with Struts in a
092: * Servlet 2.2 container, and for providing a prototype for accessing Struts
093: * through Spring's web dispatching infrastructure!
094: *
095: * @author Juergen Hoeller
096: * @since 1.1.1
097: * @see ServletForwardingController
098: * @see org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor
099: * @see org.springframework.orm.hibernate.support.OpenSessionInViewFilter
100: * @see org.springframework.orm.jdo.support.OpenPersistenceManagerInViewInterceptor
101: * @see org.springframework.orm.jdo.support.OpenPersistenceManagerInViewFilter
102: */
103: public class ServletWrappingController extends AbstractController
104: implements BeanNameAware, InitializingBean, DisposableBean {
105:
106: private Class servletClass;
107:
108: private String servletName;
109:
110: private Properties initParameters = new Properties();
111:
112: private String beanName;
113:
114: private Servlet servletInstance;
115:
116: /**
117: * Set the class of the servlet to wrap.
118: * Needs to implement <code>javax.servlet.Servlet</code>.
119: * @see javax.servlet.Servlet
120: */
121: public void setServletClass(Class servletClass) {
122: this .servletClass = servletClass;
123: }
124:
125: /**
126: * Set the name of the servlet to wrap.
127: * Default is the bean name of this controller.
128: */
129: public void setServletName(String servletName) {
130: this .servletName = servletName;
131: }
132:
133: /**
134: * Specify init parameters for the servlet to wrap,
135: * as name-value pairs.
136: */
137: public void setInitParameters(Properties initParameters) {
138: this .initParameters = initParameters;
139: }
140:
141: public void setBeanName(String name) {
142: this .beanName = name;
143: }
144:
145: /**
146: * Initialize the wrapped Servlet instance.
147: * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
148: */
149: public void afterPropertiesSet() throws Exception {
150: if (this .servletClass == null) {
151: throw new IllegalArgumentException(
152: "servletClass is required");
153: }
154: if (!Servlet.class.isAssignableFrom(this .servletClass)) {
155: throw new IllegalArgumentException(
156: "servletClass ["
157: + this .servletClass.getName()
158: + "] needs to implement interface [javax.servlet.Servlet]");
159: }
160: if (this .servletName == null) {
161: this .servletName = this .beanName;
162: }
163: this .servletInstance = (Servlet) this .servletClass
164: .newInstance();
165: this .servletInstance.init(new DelegatingServletConfig());
166: }
167:
168: /**
169: * Invoke the the wrapped Servlet instance.
170: * @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
171: */
172: protected ModelAndView handleRequestInternal(
173: HttpServletRequest request, HttpServletResponse response)
174: throws Exception {
175:
176: this .servletInstance.service(request, response);
177: return null;
178: }
179:
180: /**
181: * Destroy the wrapped Servlet instance.
182: * @see javax.servlet.Servlet#destroy()
183: */
184: public void destroy() {
185: this .servletInstance.destroy();
186: }
187:
188: /**
189: * Internal implementation of the ServletConfig interface, to be passed
190: * to the wrapped servlet. Delegates to ServletWrappingController fields
191: * and methods to provide init parameters and other environment info.
192: */
193: private class DelegatingServletConfig implements ServletConfig {
194:
195: public String getServletName() {
196: return servletName;
197: }
198:
199: public ServletContext getServletContext() {
200: return ServletWrappingController.this .getServletContext();
201: }
202:
203: public String getInitParameter(String paramName) {
204: return initParameters.getProperty(paramName);
205: }
206:
207: public Enumeration getInitParameterNames() {
208: return initParameters.keys();
209: }
210: }
211:
212: }
|