4 changed files with 295 additions and 159 deletions
@ -0,0 +1,258 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2012-2014 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.boot.context.embedded; |
||||||
|
|
||||||
|
import java.util.AbstractCollection; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Comparator; |
||||||
|
import java.util.EventListener; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.LinkedHashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Map.Entry; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import javax.servlet.Filter; |
||||||
|
import javax.servlet.MultipartConfigElement; |
||||||
|
import javax.servlet.Servlet; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.ListableBeanFactory; |
||||||
|
import org.springframework.core.annotation.AnnotationAwareOrderComparator; |
||||||
|
import org.springframework.util.LinkedMultiValueMap; |
||||||
|
import org.springframework.util.MultiValueMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* A collection {@link ServletContextInitializer}s obtained from a |
||||||
|
* {@link ListableBeanFactory}. Includes all {@link ServletContextInitializer} beans and |
||||||
|
* also adapts {@link Servlet}, {@link Filter} and certain {@link EventListener} beans. |
||||||
|
* <p> |
||||||
|
* Items are sorted so that adapted beans are top ({@link Servlet}, {@link Filter} then |
||||||
|
* {@link EventListener}) and direct {@link ServletContextInitializer} beans are at the |
||||||
|
* end. Further sorting is applied within these groups using the |
||||||
|
* {@link AnnotationAwareOrderComparator}. |
||||||
|
* |
||||||
|
* |
||||||
|
* @author Dave Syer |
||||||
|
* @author Phillip Webb |
||||||
|
*/ |
||||||
|
class ServletContextInitializerBeans extends |
||||||
|
AbstractCollection<ServletContextInitializer> { |
||||||
|
|
||||||
|
static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet"; |
||||||
|
|
||||||
|
private final Set<Object> seen = new HashSet<Object>(); |
||||||
|
|
||||||
|
private final MultiValueMap<Class<?>, ServletContextInitializer> initializers; |
||||||
|
|
||||||
|
private List<ServletContextInitializer> sortedList; |
||||||
|
|
||||||
|
public ServletContextInitializerBeans(ListableBeanFactory beanFactory) { |
||||||
|
this.initializers = new LinkedMultiValueMap<Class<?>, ServletContextInitializer>(); |
||||||
|
addServletContextInitializerBeans(beanFactory); |
||||||
|
addAdaptableBeans(beanFactory); |
||||||
|
List<ServletContextInitializer> sortedInitializers = new ArrayList<ServletContextInitializer>(); |
||||||
|
for (Map.Entry<?, List<ServletContextInitializer>> entry : this.initializers |
||||||
|
.entrySet()) { |
||||||
|
AnnotationAwareOrderComparator.sort(entry.getValue()); |
||||||
|
sortedInitializers.addAll(entry.getValue()); |
||||||
|
} |
||||||
|
this.sortedList = Collections.unmodifiableList(sortedInitializers); |
||||||
|
} |
||||||
|
|
||||||
|
private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) { |
||||||
|
for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType( |
||||||
|
beanFactory, ServletContextInitializer.class)) { |
||||||
|
addServletContextInitializerBean(initializerBean.getValue()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void addServletContextInitializerBean(ServletContextInitializer initializer) { |
||||||
|
if (initializer instanceof ServletRegistrationBean) { |
||||||
|
addServletContextInitializerBean(Servlet.class, initializer, |
||||||
|
((ServletRegistrationBean) initializer).getServlet()); |
||||||
|
} |
||||||
|
else if (initializer instanceof FilterRegistrationBean) { |
||||||
|
addServletContextInitializerBean(Filter.class, initializer, |
||||||
|
((FilterRegistrationBean) initializer).getFilter()); |
||||||
|
} |
||||||
|
else if (initializer instanceof ServletListenerRegistrationBean) { |
||||||
|
addServletContextInitializerBean(EventListener.class, initializer, |
||||||
|
((ServletListenerRegistrationBean<?>) initializer).getListener()); |
||||||
|
} |
||||||
|
else { |
||||||
|
addServletContextInitializerBean(ServletContextInitializer.class, |
||||||
|
initializer, null); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void addServletContextInitializerBean(Class<?> type, |
||||||
|
ServletContextInitializer initializer, Object source) { |
||||||
|
this.initializers.add(type, initializer); |
||||||
|
if (source != null) { |
||||||
|
// Mark the underlying source as seen in case it wraps an existing bean
|
||||||
|
this.seen.add(source); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") |
||||||
|
private void addAdaptableBeans(ListableBeanFactory beanFactory) { |
||||||
|
MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory); |
||||||
|
addAsRegistrationBean(beanFactory, Servlet.class, |
||||||
|
new ServletRegistrationBeanAdapter(multipartConfig)); |
||||||
|
addAsRegistrationBean(beanFactory, Filter.class, |
||||||
|
new FilterRegistrationBeanAdapter()); |
||||||
|
for (Class<?> listenerType : ServletListenerRegistrationBean.getSupportedTypes()) { |
||||||
|
addAsRegistrationBean(beanFactory, EventListener.class, |
||||||
|
(Class<EventListener>) listenerType, |
||||||
|
new ServletListenerRegistrationBeanAdapter()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private MultipartConfigElement getMultipartConfig(ListableBeanFactory beanFactory) { |
||||||
|
List<Entry<String, MultipartConfigElement>> beans = getOrderedBeansOfType( |
||||||
|
beanFactory, MultipartConfigElement.class); |
||||||
|
return (beans.isEmpty() ? null : beans.get(0).getValue()); |
||||||
|
} |
||||||
|
|
||||||
|
private <T> void addAsRegistrationBean(ListableBeanFactory beanFactory, |
||||||
|
Class<T> type, RegistrationBeanAdapter<T> adapter) { |
||||||
|
addAsRegistrationBean(beanFactory, type, type, adapter); |
||||||
|
} |
||||||
|
|
||||||
|
private <T, B extends T> void addAsRegistrationBean(ListableBeanFactory beanFactory, |
||||||
|
Class<T> type, Class<B> beanType, RegistrationBeanAdapter<T> adapter) { |
||||||
|
List<Map.Entry<String, B>> beans = getOrderedBeansOfType(beanFactory, beanType); |
||||||
|
for (Entry<String, B> bean : beans) { |
||||||
|
if (this.seen.add(bean.getValue())) { |
||||||
|
// One that we haven't already seen
|
||||||
|
RegistrationBean registration = adapter.createRegistrationBean( |
||||||
|
bean.getKey(), bean.getValue(), beans.size()); |
||||||
|
registration.setName(bean.getKey()); |
||||||
|
registration.setOrder(getOrder(bean.getValue())); |
||||||
|
this.initializers.add(type, registration); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private int getOrder(Object value) { |
||||||
|
return new AnnotationAwareOrderComparator() { |
||||||
|
@Override |
||||||
|
public int getOrder(Object obj) { |
||||||
|
return super.getOrder(obj); |
||||||
|
} |
||||||
|
}.getOrder(value); |
||||||
|
} |
||||||
|
|
||||||
|
private <T> List<Entry<String, T>> getOrderedBeansOfType( |
||||||
|
ListableBeanFactory beanFactory, Class<T> type) { |
||||||
|
List<Entry<String, T>> beans = new ArrayList<Entry<String, T>>(); |
||||||
|
Comparator<Entry<String, T>> comparator = new Comparator<Entry<String, T>>() { |
||||||
|
@Override |
||||||
|
public int compare(Entry<String, T> o1, Entry<String, T> o2) { |
||||||
|
return AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(), |
||||||
|
o2.getValue()); |
||||||
|
} |
||||||
|
}; |
||||||
|
String[] names = beanFactory.getBeanNamesForType(type, true, false); |
||||||
|
Map<String, T> map = new LinkedHashMap<String, T>(); |
||||||
|
for (String name : names) { |
||||||
|
map.put(name, beanFactory.getBean(name, type)); |
||||||
|
} |
||||||
|
beans.addAll(map.entrySet()); |
||||||
|
Collections.sort(beans, comparator); |
||||||
|
return beans; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Iterator<ServletContextInitializer> iterator() { |
||||||
|
return this.sortedList.iterator(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int size() { |
||||||
|
return this.sortedList.size(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adapter to convert a given Bean type into a {@link RegistrationBean} (and hence a |
||||||
|
* {@link ServletContextInitializer}. |
||||||
|
*/ |
||||||
|
private static interface RegistrationBeanAdapter<T> { |
||||||
|
|
||||||
|
RegistrationBean createRegistrationBean(String name, T source, |
||||||
|
int totalNumberOfSourceBeans); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link RegistrationBeanAdapter} for {@link Servlet} beans. |
||||||
|
*/ |
||||||
|
private static class ServletRegistrationBeanAdapter implements |
||||||
|
RegistrationBeanAdapter<Servlet> { |
||||||
|
|
||||||
|
private final MultipartConfigElement multipartConfig; |
||||||
|
|
||||||
|
public ServletRegistrationBeanAdapter(MultipartConfigElement multipartConfig) { |
||||||
|
this.multipartConfig = multipartConfig; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public RegistrationBean createRegistrationBean(String name, Servlet source, |
||||||
|
int totalNumberOfSourceBeans) { |
||||||
|
String url = (totalNumberOfSourceBeans == 1 ? "/" : "/" + name + "/"); |
||||||
|
if (name.equals(DISPATCHER_SERVLET_NAME)) { |
||||||
|
url = "/"; // always map the main dispatcherServlet to "/"
|
||||||
|
} |
||||||
|
ServletRegistrationBean bean = new ServletRegistrationBean(source, url); |
||||||
|
bean.setMultipartConfig(this.multipartConfig); |
||||||
|
return bean; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link RegistrationBeanAdapter} for {@link Filter} beans. |
||||||
|
*/ |
||||||
|
private static class FilterRegistrationBeanAdapter implements |
||||||
|
RegistrationBeanAdapter<Filter> { |
||||||
|
|
||||||
|
@Override |
||||||
|
public RegistrationBean createRegistrationBean(String name, Filter source, |
||||||
|
int totalNumberOfSourceBeans) { |
||||||
|
return new FilterRegistrationBean(source); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link RegistrationBeanAdapter} for certain {@link EventListener} beans. |
||||||
|
*/ |
||||||
|
private static class ServletListenerRegistrationBeanAdapter implements |
||||||
|
RegistrationBeanAdapter<EventListener> { |
||||||
|
|
||||||
|
@Override |
||||||
|
public RegistrationBean createRegistrationBean(String name, EventListener source, |
||||||
|
int totalNumberOfSourceBeans) { |
||||||
|
return new ServletListenerRegistrationBean<EventListener>(source); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue