/* * Copyright 2013 Atteo. * * 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.atteo.moonshine.webserver; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.EventListener; import java.util.List; import java.util.Map; import java.util.Set; import javax.inject.Provider; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterRegistration; import javax.servlet.Servlet; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import org.atteo.moonshine.TopLevelService; import com.google.inject.servlet.GuiceFilter; import com.google.inject.servlet.ServletModule; /** * Allows configuration of servlets, filters and listeners. */ @XmlRootElement(name = "servlet-container") public class ServletContainer extends TopLevelService { /** * Default priority assigned to filters. */ public static final int DEFAULT_PRIORITY = 0; /** * Add {@link GuiceFilter}. When true servlets and filters registered * using {@link ServletModule}s will be accessible under this context. */ @XmlElement private boolean registerGuiceFilter = false; private final List<ServletOrFilterDefinition<? extends Servlet>> servlets = new ArrayList<>(); private final List<ServletOrFilterDefinition<? extends Filter>> filters = new ArrayList<>(); private final List<Provider<? extends EventListener>> listeners = new ArrayList<>(); private final List<ServletContainerInitializer> initializers = new ArrayList<>(); public ServletContainer() { initializers.add(new Initializer()); } /** * Register servlet. * * @param patterns URL pattern to register servlet onto * @param servlet servlet */ public <T extends Servlet> void addServlet(T servlet, String... patterns) { addServlet(servlet, Collections.<String, String>emptyMap(), patterns); } /** * Register servlet. * * @param patterns URL pattern to register servlet onto * @param servlet servlet provider */ public <T extends Servlet> void addServlet(Provider<T> servlet, String... patterns) { addServlet(servlet, Collections.<String, String>emptyMap(), patterns); } /** * Register servlet. * * @param patterns URL pattern to register servlet onto * @param servlet servlet * @param params servlet init parameters */ public <T extends Servlet> void addServlet(final T servlet, Map<String, String> params, String... patterns) { Provider<T> provider = () -> servlet; servlets.add(new ServletOrFilterDefinition<>(provider, params, patterns, DEFAULT_PRIORITY)); } /** * Register servlet. * * @param patterns URL pattern to register servlet onto * @param servlet servlet provider * @param params servlet init parameters */ public <T extends Servlet> void addServlet(Provider<T> servlet, Map<String, String> params, String... patterns) { servlets.add(new ServletOrFilterDefinition<>(servlet, params, patterns, DEFAULT_PRIORITY)); } /** * Register filter. It will be assigned the default priority. * * @param patterns URL pattern to register filter onto * @param filter filter */ public <T extends Filter> void addFilter(T filter, String patterns) { addFilter(filter, Collections.<String, String>emptyMap(), DEFAULT_PRIORITY, patterns); } /** * Register filter. It will be assigned the default priority. * * @param patterns URL pattern to register filter onto * @param filter filter provider */ public <T extends Filter> void addFilter(Provider<T> filter, String... patterns) { addFilter(filter, Collections.<String, String>emptyMap(), DEFAULT_PRIORITY, patterns); } /** * Register filter. * * @param patterns URL pattern to register filter onto * @param filter filter * @param params filter init parameters */ public <T extends Filter> void addFilter(final T filter, Map<String, String> params, String... patterns) { addFilter(filter, params, DEFAULT_PRIORITY, patterns); } /** * Register filter. * * @param patterns URL pattern to register filter onto * @param filter filter provider * @param params filter init parameters */ public <T extends Filter> void addFilter(Provider<T> filter, Map<String, String> params, String... patterns) { addFilter(filter, params, DEFAULT_PRIORITY, patterns); } /** * Register filter. * * @param patterns URL pattern to register filter onto * @param filter filter * @param priority filter priority, filters with lower priorities are * executed first * @param params filter init parameters */ public <T extends Filter> void addFilter(final T filter, Map<String, String> params, int priority, String... patterns) { Provider<T> provider = () -> filter; filters.add(new ServletOrFilterDefinition<>(provider, params, patterns, priority)); } /** * Register filter. * * @param patterns URL pattern to register filter onto * @param filter filter provider * @param priority filter priority, filters with lower priorities are * executed first * @param params filter init parameters */ public <T extends Filter> void addFilter(Provider<T> filter, Map<String, String> params, int priority, String... patterns) { filters.add(new ServletOrFilterDefinition<>(filter, params, patterns, priority)); } /** * Register listener. * * @param listener listener provider */ public <T extends EventListener> void addListener(Provider<T> listener) { listeners.add(listener); } /** * Register listener. * * @param listener listener to register */ public <T extends EventListener> void addListener(final T listener) { listeners.add((Provider<T>) () -> listener); } public void addServletContainerInitializer(ServletContainerInitializer initializer) { initializers.add(initializer); } public Iterable<ServletContainerInitializer> getInitializers() { return initializers; } private class Initializer implements ServletContainerInitializer { @Override public void onStartup(Set<Class<?>> c, ServletContext context) throws ServletException { if (registerGuiceFilter) { FilterRegistration.Dynamic registration = context.addFilter("guice-filter", GuiceFilter.class); registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*"); } // sort filters by priority Collections.sort(filters); int counter = 0; for (ServletOrFilterDefinition<? extends Filter> filter : filters) { String name = "filter" + counter; counter++; FilterRegistration.Dynamic registration = context.addFilter(name, filter.getProvider().get()); registration.setInitParameters(filter.getParams()); registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, filter.getPatterns()); } counter = 0; for (ServletOrFilterDefinition<? extends Servlet> servlet : servlets) { String name = "servlet" + counter; counter++; ServletRegistration.Dynamic registration = context.addServlet(name, servlet.getProvider().get()); registration.setInitParameters(servlet.getParams()); registration.addMapping(servlet.getPatterns()); } for (Provider<? extends EventListener> listener : listeners) { context.addListener(listener.get()); } } } }