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

package org.springframework.web.servlet;

import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceEditor;
import org.springframework.core.io.ResourceLoader;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.ServletContextResourceLoader;
import org.springframework.web.context.support.StandardServletEnvironment;

Simple extension of HttpServlet which treats its config parameters (init-param entries within the servlet tag in web.xml) as bean properties.

A handy superclass for any type of servlet. Type conversion of config parameters is automatic, with the corresponding setter method getting invoked with the converted value. It is also possible for subclasses to specify required properties. Parameters without matching bean property setter will simply be ignored.

This servlet leaves request handling to subclasses, inheriting the default behavior of HttpServlet (doGet, doPost, etc).

This generic servlet base class has no dependency on the Spring ApplicationContext concept. Simple servlets usually don't load their own context but rather access service beans from the Spring root application context, accessible via the filter's ServletContext (see WebApplicationContextUtils).

The FrameworkServlet class is a more specific servlet base class which loads its own application context. FrameworkServlet serves as direct base class of Spring's full-fledged DispatcherServlet.

Author:Rod Johnson, Juergen Hoeller
See Also:
/** * Simple extension of {@link javax.servlet.http.HttpServlet} which treats * its config parameters ({@code init-param} entries within the * {@code servlet} tag in {@code web.xml}) as bean properties. * * <p>A handy superclass for any type of servlet. Type conversion of config * parameters is automatic, with the corresponding setter method getting * invoked with the converted value. It is also possible for subclasses to * specify required properties. Parameters without matching bean property * setter will simply be ignored. * * <p>This servlet leaves request handling to subclasses, inheriting the default * behavior of HttpServlet ({@code doGet}, {@code doPost}, etc). * * <p>This generic servlet base class has no dependency on the Spring * {@link org.springframework.context.ApplicationContext} concept. Simple * servlets usually don't load their own context but rather access service * beans from the Spring root application context, accessible via the * filter's {@link #getServletContext() ServletContext} (see * {@link org.springframework.web.context.support.WebApplicationContextUtils}). * * <p>The {@link FrameworkServlet} class is a more specific servlet base * class which loads its own application context. FrameworkServlet serves * as direct base class of Spring's full-fledged {@link DispatcherServlet}. * * @author Rod Johnson * @author Juergen Hoeller * @see #addRequiredProperty * @see #initServletBean * @see #doGet * @see #doPost */
@SuppressWarnings("serial") public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
Logger available to subclasses.
/** Logger available to subclasses. */
protected final Log logger = LogFactory.getLog(getClass()); @Nullable private ConfigurableEnvironment environment; private final Set<String> requiredProperties = new HashSet<>(4);
Subclasses can invoke this method to specify that this property (which must match a JavaBean property they expose) is mandatory, and must be supplied as a config parameter. This should be called from the constructor of a subclass.

This method is only relevant in case of traditional initialization driven by a ServletConfig instance.

Params:
  • property – name of the required property
/** * Subclasses can invoke this method to specify that this property * (which must match a JavaBean property they expose) is mandatory, * and must be supplied as a config parameter. This should be called * from the constructor of a subclass. * <p>This method is only relevant in case of traditional initialization * driven by a ServletConfig instance. * @param property name of the required property */
protected final void addRequiredProperty(String property) { this.requiredProperties.add(property); }
Set the Environment that this servlet runs in.

Any environment set here overrides the StandardServletEnvironment provided by default.

Throws:
/** * Set the {@code Environment} that this servlet runs in. * <p>Any environment set here overrides the {@link StandardServletEnvironment} * provided by default. * @throws IllegalArgumentException if environment is not assignable to * {@code ConfigurableEnvironment} */
@Override public void setEnvironment(Environment environment) { Assert.isInstanceOf(ConfigurableEnvironment.class, environment, "ConfigurableEnvironment required"); this.environment = (ConfigurableEnvironment) environment; }
Return the Environment associated with this servlet.

If none specified, a default environment will be initialized via createEnvironment().

/** * Return the {@link Environment} associated with this servlet. * <p>If none specified, a default environment will be initialized via * {@link #createEnvironment()}. */
@Override public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = createEnvironment(); } return this.environment; }
Create and return a new StandardServletEnvironment.

Subclasses may override this in order to configure the environment or specialize the environment type returned.

/** * Create and return a new {@link StandardServletEnvironment}. * <p>Subclasses may override this in order to configure the environment or * specialize the environment type returned. */
protected ConfigurableEnvironment createEnvironment() { return new StandardServletEnvironment(); }
Map config parameters onto bean properties of this servlet, and invoke subclass initialization.
Throws:
  • ServletException – if bean properties are invalid (or required properties are missing), or if subclass initialization fails.
/** * Map config parameters onto bean properties of this servlet, and * invoke subclass initialization. * @throws ServletException if bean properties are invalid (or required * properties are missing), or if subclass initialization fails. */
@Override public final void init() throws ServletException { // Set bean properties from init parameters. PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); if (!pvs.isEmpty()) { try { BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); initBeanWrapper(bw); bw.setPropertyValues(pvs, true); } catch (BeansException ex) { if (logger.isErrorEnabled()) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); } throw ex; } } // Let subclasses do whatever initialization they like. initServletBean(); }
Initialize the BeanWrapper for this HttpServletBean, possibly with custom editors.

This default implementation is empty.

Params:
  • bw – the BeanWrapper to initialize
Throws:
See Also:
/** * Initialize the BeanWrapper for this HttpServletBean, * possibly with custom editors. * <p>This default implementation is empty. * @param bw the BeanWrapper to initialize * @throws BeansException if thrown by BeanWrapper methods * @see org.springframework.beans.BeanWrapper#registerCustomEditor */
protected void initBeanWrapper(BeanWrapper bw) throws BeansException { }
Subclasses may override this to perform custom initialization. All bean properties of this servlet will have been set before this method is invoked.

This default implementation is empty.

Throws:
  • ServletException – if subclass initialization fails
/** * Subclasses may override this to perform custom initialization. * All bean properties of this servlet will have been set before this * method is invoked. * <p>This default implementation is empty. * @throws ServletException if subclass initialization fails */
protected void initServletBean() throws ServletException { }
Overridden method that simply returns null when no ServletConfig set yet.
See Also:
/** * Overridden method that simply returns {@code null} when no * ServletConfig set yet. * @see #getServletConfig() */
@Override @Nullable public String getServletName() { return (getServletConfig() != null ? getServletConfig().getServletName() : null); }
PropertyValues implementation created from ServletConfig init parameters.
/** * PropertyValues implementation created from ServletConfig init parameters. */
private static class ServletConfigPropertyValues extends MutablePropertyValues {
Create new ServletConfigPropertyValues.
Params:
  • config – the ServletConfig we'll use to take PropertyValues from
  • requiredProperties – set of property names we need, where we can't accept default values
Throws:
/** * Create new ServletConfigPropertyValues. * @param config the ServletConfig we'll use to take PropertyValues from * @param requiredProperties set of property names we need, where * we can't accept default values * @throws ServletException if any required properties are missing */
public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties) throws ServletException { Set<String> missingProps = (!CollectionUtils.isEmpty(requiredProperties) ? new HashSet<>(requiredProperties) : null); Enumeration<String> paramNames = config.getInitParameterNames(); while (paramNames.hasMoreElements()) { String property = paramNames.nextElement(); Object value = config.getInitParameter(property); addPropertyValue(new PropertyValue(property, value)); if (missingProps != null) { missingProps.remove(property); } } // Fail if we are still missing properties. if (!CollectionUtils.isEmpty(missingProps)) { throw new ServletException( "Initialization from ServletConfig for servlet '" + config.getServletName() + "' failed; the following required properties were missing: " + StringUtils.collectionToDelimitedString(missingProps, ", ")); } } } }