001/* 002 * Copyright 2012-2018 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 017package org.springframework.boot.web.servlet; 018 019import java.util.Collections; 020import java.util.EventListener; 021import java.util.HashSet; 022import java.util.Set; 023 024import javax.servlet.ServletContext; 025import javax.servlet.ServletContextAttributeListener; 026import javax.servlet.ServletContextListener; 027import javax.servlet.ServletRequestAttributeListener; 028import javax.servlet.ServletRequestListener; 029import javax.servlet.http.HttpSessionAttributeListener; 030import javax.servlet.http.HttpSessionListener; 031 032import org.springframework.util.Assert; 033import org.springframework.util.ClassUtils; 034 035/** 036 * A {@link ServletContextInitializer} to register {@link EventListener}s in a Servlet 037 * 3.0+ container. Similar to the {@link ServletContext#addListener(EventListener) 038 * registration} features provided by {@link ServletContext} but with a Spring Bean 039 * friendly design. 040 * 041 * This bean can be used to register the following types of listener: 042 * <ul> 043 * <li>{@link ServletContextAttributeListener}</li> 044 * <li>{@link ServletRequestListener}</li> 045 * <li>{@link ServletRequestAttributeListener}</li> 046 * <li>{@link HttpSessionAttributeListener}</li> 047 * <li>{@link HttpSessionListener}</li> 048 * <li>{@link ServletContextListener}</li> 049 * </ul> 050 * 051 * @param <T> the type of listener 052 * @author Dave Syer 053 * @author Phillip Webb 054 * @since 1.4.0 055 */ 056public class ServletListenerRegistrationBean<T extends EventListener> 057 extends RegistrationBean { 058 059 private static final Set<Class<?>> SUPPORTED_TYPES; 060 061 static { 062 Set<Class<?>> types = new HashSet<>(); 063 types.add(ServletContextAttributeListener.class); 064 types.add(ServletRequestListener.class); 065 types.add(ServletRequestAttributeListener.class); 066 types.add(HttpSessionAttributeListener.class); 067 types.add(HttpSessionListener.class); 068 types.add(ServletContextListener.class); 069 SUPPORTED_TYPES = Collections.unmodifiableSet(types); 070 } 071 072 private T listener; 073 074 /** 075 * Create a new {@link ServletListenerRegistrationBean} instance. 076 */ 077 public ServletListenerRegistrationBean() { 078 } 079 080 /** 081 * Create a new {@link ServletListenerRegistrationBean} instance. 082 * @param listener the listener to register 083 */ 084 public ServletListenerRegistrationBean(T listener) { 085 Assert.notNull(listener, "Listener must not be null"); 086 Assert.isTrue(isSupportedType(listener), "Listener is not of a supported type"); 087 this.listener = listener; 088 } 089 090 /** 091 * Set the listener that will be registered. 092 * @param listener the listener to register 093 */ 094 public void setListener(T listener) { 095 Assert.notNull(listener, "Listener must not be null"); 096 Assert.isTrue(isSupportedType(listener), "Listener is not of a supported type"); 097 this.listener = listener; 098 } 099 100 /** 101 * Return the listener to be registered. 102 * @return the listener to be registered 103 */ 104 public T getListener() { 105 return this.listener; 106 } 107 108 @Override 109 protected String getDescription() { 110 Assert.notNull(this.listener, "Listener must not be null"); 111 return "listener " + this.listener; 112 } 113 114 @Override 115 protected void register(String description, ServletContext servletContext) { 116 try { 117 servletContext.addListener(this.listener); 118 } 119 catch (RuntimeException ex) { 120 throw new IllegalStateException( 121 "Failed to add listener '" + this.listener + "' to servlet context", 122 ex); 123 } 124 } 125 126 /** 127 * Returns {@code true} if the specified listener is one of the supported types. 128 * @param listener the listener to test 129 * @return if the listener is of a supported type 130 */ 131 public static boolean isSupportedType(EventListener listener) { 132 for (Class<?> type : SUPPORTED_TYPES) { 133 if (ClassUtils.isAssignableValue(type, listener)) { 134 return true; 135 } 136 } 137 return false; 138 } 139 140 /** 141 * Return the supported types for this registration. 142 * @return the supported types 143 */ 144 public static Set<Class<?>> getSupportedTypes() { 145 return SUPPORTED_TYPES; 146 } 147 148}