001/*
002 * Copyright 2002-2016 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 *      https://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
017package org.springframework.web.servlet.mvc;
018
019import java.util.Enumeration;
020import java.util.Properties;
021import javax.servlet.Servlet;
022import javax.servlet.ServletConfig;
023import javax.servlet.ServletContext;
024import javax.servlet.http.HttpServletRequest;
025import javax.servlet.http.HttpServletResponse;
026
027import org.springframework.beans.factory.BeanNameAware;
028import org.springframework.beans.factory.DisposableBean;
029import org.springframework.beans.factory.InitializingBean;
030import org.springframework.web.servlet.ModelAndView;
031
032/**
033 * Spring Controller implementation that wraps a servlet instance which it manages
034 * internally. Such a wrapped servlet is not known outside of this controller;
035 * its entire lifecycle is covered here (in contrast to {@link ServletForwardingController}).
036 *
037 * <p>Useful to invoke an existing servlet via Spring's dispatching infrastructure,
038 * for example to apply Spring HandlerInterceptors to its requests.
039 *
040 * <p>Note that Struts has a special requirement in that it parses {@code web.xml}
041 * to find its servlet mapping. Therefore, you need to specify the DispatcherServlet's
042 * servlet name as "servletName" on this controller, so that Struts finds the
043 * DispatcherServlet's mapping (thinking that it refers to the ActionServlet).
044 *
045 * <p><b>Example:</b> a DispatcherServlet XML context, forwarding "*.do" to the Struts
046 * ActionServlet wrapped by a ServletWrappingController. All such requests will go
047 * through the configured HandlerInterceptor chain (e.g. an OpenSessionInViewInterceptor).
048 * From the Struts point of view, everything will work as usual.
049 *
050 * <pre class="code">
051 * &lt;bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;
052 *   &lt;property name="interceptors"&gt;
053 *     &lt;list&gt;
054 *       &lt;ref bean="openSessionInViewInterceptor"/&gt;
055 *     &lt;/list&gt;
056 *   &lt;/property&gt;
057 *   &lt;property name="mappings"&gt;
058 *     &lt;props&gt;
059 *       &lt;prop key="*.do"&gt;strutsWrappingController&lt;/prop&gt;
060 *     &lt;/props&gt;
061 *   &lt;/property&gt;
062 * &lt;/bean&gt;
063 *
064 * &lt;bean id="strutsWrappingController" class="org.springframework.web.servlet.mvc.ServletWrappingController"&gt;
065 *   &lt;property name="servletClass"&gt;
066 *     &lt;value&gt;org.apache.struts.action.ActionServlet&lt;/value&gt;
067 *   &lt;/property&gt;
068 *   &lt;property name="servletName"&gt;
069 *     &lt;value&gt;action&lt;/value&gt;
070 *   &lt;/property&gt;
071 *   &lt;property name="initParameters"&gt;
072 *     &lt;props&gt;
073 *       &lt;prop key="config"&gt;/WEB-INF/struts-config.xml&lt;/prop&gt;
074 *     &lt;/props&gt;
075 *   &lt;/property&gt;
076 * &lt;/bean&gt;</pre>
077 *
078 * @author Juergen Hoeller
079 * @since 1.1.1
080 * @see ServletForwardingController
081 */
082public class ServletWrappingController extends AbstractController
083                implements BeanNameAware, InitializingBean, DisposableBean {
084
085        private Class<? extends Servlet> servletClass;
086
087        private String servletName;
088
089        private Properties initParameters = new Properties();
090
091        private String beanName;
092
093        private Servlet servletInstance;
094
095
096        public ServletWrappingController() {
097                super(false);
098        }
099
100
101        /**
102         * Set the class of the servlet to wrap.
103         * Needs to implement {@code javax.servlet.Servlet}.
104         * @see javax.servlet.Servlet
105         */
106        public void setServletClass(Class<? extends Servlet> servletClass) {
107                this.servletClass = servletClass;
108        }
109
110        /**
111         * Set the name of the servlet to wrap.
112         * Default is the bean name of this controller.
113         */
114        public void setServletName(String servletName) {
115                this.servletName = servletName;
116        }
117
118        /**
119         * Specify init parameters for the servlet to wrap,
120         * as name-value pairs.
121         */
122        public void setInitParameters(Properties initParameters) {
123                this.initParameters = initParameters;
124        }
125
126        @Override
127        public void setBeanName(String name) {
128                this.beanName = name;
129        }
130
131
132        /**
133         * Initialize the wrapped Servlet instance.
134         * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
135         */
136        @Override
137        public void afterPropertiesSet() throws Exception {
138                if (this.servletClass == null) {
139                        throw new IllegalArgumentException("'servletClass' is required");
140                }
141                if (this.servletName == null) {
142                        this.servletName = this.beanName;
143                }
144                this.servletInstance = this.servletClass.newInstance();
145                this.servletInstance.init(new DelegatingServletConfig());
146        }
147
148
149        /**
150         * Invoke the wrapped Servlet instance.
151         * @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
152         */
153        @Override
154        protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
155                        throws Exception {
156
157                this.servletInstance.service(request, response);
158                return null;
159        }
160
161
162        /**
163         * Destroy the wrapped Servlet instance.
164         * @see javax.servlet.Servlet#destroy()
165         */
166        @Override
167        public void destroy() {
168                this.servletInstance.destroy();
169        }
170
171
172        /**
173         * Internal implementation of the ServletConfig interface, to be passed
174         * to the wrapped servlet. Delegates to ServletWrappingController fields
175         * and methods to provide init parameters and other environment info.
176         */
177        private class DelegatingServletConfig implements ServletConfig {
178
179                @Override
180                public String getServletName() {
181                        return servletName;
182                }
183
184                @Override
185                public ServletContext getServletContext() {
186                        return ServletWrappingController.this.getServletContext();
187                }
188
189                @Override
190                public String getInitParameter(String paramName) {
191                        return initParameters.getProperty(paramName);
192                }
193
194                @Override
195                @SuppressWarnings({ "unchecked", "rawtypes" })
196                public Enumeration<String> getInitParameterNames() {
197                        return (Enumeration) initParameters.keys();
198                }
199        }
200
201}