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 * <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 052 * <property name="interceptors"> 053 * <list> 054 * <ref bean="openSessionInViewInterceptor"/> 055 * </list> 056 * </property> 057 * <property name="mappings"> 058 * <props> 059 * <prop key="*.do">strutsWrappingController</prop> 060 * </props> 061 * </property> 062 * </bean> 063 * 064 * <bean id="strutsWrappingController" class="org.springframework.web.servlet.mvc.ServletWrappingController"> 065 * <property name="servletClass"> 066 * <value>org.apache.struts.action.ActionServlet</value> 067 * </property> 068 * <property name="servletName"> 069 * <value>action</value> 070 * </property> 071 * <property name="initParameters"> 072 * <props> 073 * <prop key="config">/WEB-INF/struts-config.xml</prop> 074 * </props> 075 * </property> 076 * </bean></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}