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.handler;
018
019import java.util.Collections;
020import java.util.Enumeration;
021import javax.servlet.Servlet;
022import javax.servlet.ServletConfig;
023import javax.servlet.ServletContext;
024import javax.servlet.ServletException;
025
026import org.springframework.beans.BeansException;
027import org.springframework.beans.factory.BeanInitializationException;
028import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
029import org.springframework.web.context.ServletConfigAware;
030import org.springframework.web.context.ServletContextAware;
031
032/**
033 * {@link org.springframework.beans.factory.config.BeanPostProcessor}
034 * that applies initialization and destruction callbacks to beans that
035 * implement the {@link javax.servlet.Servlet} interface.
036 *
037 * <p>After initialization of the bean instance, the Servlet {@code init}
038 * method will be called with a ServletConfig that contains the bean name
039 * of the Servlet and the ServletContext that it is running in.
040 *
041 * <p>Before destruction of the bean instance, the Servlet {@code destroy}
042 * will be called.
043 *
044 * <p><b>Note that this post-processor does not support Servlet initialization
045 * parameters.</b> Bean instances that implement the Servlet interface are
046 * supposed to be configured like any other Spring bean, that is, through
047 * constructor arguments or bean properties.
048 *
049 * <p>For reuse of a Servlet implementation in a plain Servlet container
050 * and as a bean in a Spring context, consider deriving from Spring's
051 * {@link org.springframework.web.servlet.HttpServletBean} base class that
052 * applies Servlet initialization parameters as bean properties, supporting
053 * both the standard Servlet and the Spring bean initialization style.
054 *
055 * <p><b>Alternatively, consider wrapping a Servlet with Spring's
056 * {@link org.springframework.web.servlet.mvc.ServletWrappingController}.</b>
057 * This is particularly appropriate for existing Servlet classes,
058 * allowing to specify Servlet initialization parameters etc.
059 *
060 * @author Juergen Hoeller
061 * @since 1.1.5
062 * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
063 * @see javax.servlet.Servlet#destroy()
064 * @see SimpleServletHandlerAdapter
065 */
066public class SimpleServletPostProcessor implements
067                DestructionAwareBeanPostProcessor, ServletContextAware, ServletConfigAware {
068
069        private boolean useSharedServletConfig = true;
070
071        private ServletContext servletContext;
072
073        private ServletConfig servletConfig;
074
075
076        /**
077         * Set whether to use the shared ServletConfig object passed in
078         * through {@code setServletConfig}, if available.
079         * <p>Default is "true". Turn this setting to "false" to pass in
080         * a mock ServletConfig object with the bean name as servlet name,
081         * holding the current ServletContext.
082         * @see #setServletConfig
083         */
084        public void setUseSharedServletConfig(boolean useSharedServletConfig) {
085                this.useSharedServletConfig = useSharedServletConfig;
086        }
087
088        @Override
089        public void setServletContext(ServletContext servletContext) {
090                this.servletContext = servletContext;
091        }
092
093        @Override
094        public void setServletConfig(ServletConfig servletConfig) {
095                this.servletConfig = servletConfig;
096        }
097
098
099        @Override
100        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
101                return bean;
102        }
103
104        @Override
105        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
106                if (bean instanceof Servlet) {
107                        ServletConfig config = this.servletConfig;
108                        if (config == null || !this.useSharedServletConfig) {
109                                config = new DelegatingServletConfig(beanName, this.servletContext);
110                        }
111                        try {
112                                ((Servlet) bean).init(config);
113                        }
114                        catch (ServletException ex) {
115                                throw new BeanInitializationException("Servlet.init threw exception", ex);
116                        }
117                }
118                return bean;
119        }
120
121        @Override
122        public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
123                if (bean instanceof Servlet) {
124                        ((Servlet) bean).destroy();
125                }
126        }
127
128        @Override
129        public boolean requiresDestruction(Object bean) {
130                return (bean instanceof Servlet);
131        }
132
133
134        /**
135         * Internal implementation of the {@link ServletConfig} interface,
136         * to be passed to the wrapped servlet.
137         */
138        private static class DelegatingServletConfig implements ServletConfig {
139
140                private final String servletName;
141
142                private final ServletContext servletContext;
143
144                public DelegatingServletConfig(String servletName, ServletContext servletContext) {
145                        this.servletName = servletName;
146                        this.servletContext = servletContext;
147                }
148
149                @Override
150                public String getServletName() {
151                        return this.servletName;
152                }
153
154                @Override
155                public ServletContext getServletContext() {
156                        return this.servletContext;
157                }
158
159                @Override
160                public String getInitParameter(String paramName) {
161                        return null;
162                }
163
164                @Override
165                public Enumeration<String> getInitParameterNames() {
166                        return Collections.enumeration(Collections.<String>emptySet());
167                }
168        }
169
170}