/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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.jboss.weld.environment.servlet;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import javax.enterprise.inject.spi.BeanManager;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.http.HttpSessionEvent;
import org.jboss.weld.environment.ContainerInstance;
import org.jboss.weld.environment.ContainerInstanceFactory;
import org.jboss.weld.environment.servlet.logging.WeldServletLogger;
import org.jboss.weld.servlet.api.ServletListener;
import org.jboss.weld.servlet.api.helpers.ForwardingServletListener;
import org.jboss.weld.util.Preconditions;
/**
* This is the original listener which had to be defined in web.xml.
*
* It's not necessary to register this listener in Servlet 3.0 compliant containers unless there are listener ordering conflicts. E.g. if a user provides a
* custom listener the request context will not be active during its notifications. In this case place this listener before any other listener definitions in
* web.xml.
*
* {@link ServletContextListener#contextInitialized(ServletContextEvent)} is no-op in case of the {@link EnhancedListener} is registered as well.
*
* @author Pete Muir
* @author Ales Justin
* @see EnhancedListener
*/
public class Listener extends ForwardingServletListener {
public static final String CONTAINER_ATTRIBUTE_NAME = WeldServletLifecycle.class.getPackage().getName() + ".container";
static final String LISTENER_USED_ATTRIBUTE_NAME = EnhancedListener.class.getPackage().getName() + ".listenerUsed";
/**
* Creates a new Listener that uses the given {@link BeanManager} instead of initializing a new Weld container instance.
*
* @param manager the bean manager to be used
* @return a new Listener instance
*/
public static Listener using(BeanManager manager) {
return new Listener(Collections.singletonList(initAction(WeldServletLifecycle.BEAN_MANAGER_ATTRIBUTE_NAME, manager)));
}
/**
* Creates a new Listener that uses the given {@link ContainerInstance} (e.g. {@link org.jboss.weld.environment.se.WeldContainer}) instead of initializing a
* new Weld container instance. The listener does not take over the responsibility for container instance lifecycle management. It is the caller's
* responsibility to shut down the container instance properly. The listener will not shut down the container instance when the Servlet context is
* destroyed.
*
* @param container the container instance to be used
* @return a new Listener instance
*/
public static Listener using(ContainerInstance container) {
return new Listener(Collections.singletonList(initAction(CONTAINER_ATTRIBUTE_NAME, container)));
}
/**
* Creates a new Listener that uses the given {@link ContainerInstanceFactory} for initializing Weld instance. A new Weld instance will be initialized using
* {@link ContainerInstanceFactory#initialize()} when the Servlet context is initialized. The Weld instance will be shut down when Servlet context is
* destroyed.
*
* @param container the container factory to be used
* @return a new Listener instance
*/
public static Listener using(ContainerInstanceFactory container) {
return new Listener(Collections.singletonList(initAction(CONTAINER_ATTRIBUTE_NAME, container)));
}
private static Consumer<ServletContext> initAction(String key, Object value) {
Preconditions.checkNotNull(value);
return (context -> context.setAttribute(key, value));
}
private volatile WeldServletLifecycle lifecycle;
private final List<Consumer<ServletContext>> initActions;
public Listener() {
this.initActions = Collections.emptyList();
}
private Listener(List<Consumer<ServletContext>> initActions) {
this.initActions = initActions;
}
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
lifecycle = (WeldServletLifecycle) context.getAttribute(WeldServletLifecycle.INSTANCE_ATTRIBUTE_NAME);
context.setAttribute(LISTENER_USED_ATTRIBUTE_NAME, Boolean.TRUE);
if (Boolean.TRUE.equals(context.getAttribute(EnhancedListener.ENHANCED_LISTENER_USED_ATTRIBUTE_NAME))) {
WeldServletLogger.LOG.enhancedListenerUsedForNotifications();
return;
}
WeldServletLogger.LOG.initializeWeldUsingServletContextListener();
for (Consumer<ServletContext> initAction : initActions) {
initAction.accept(context);
}
lifecycle = new WeldServletLifecycle();
lifecycle.initialize(context);
super.contextInitialized(sce);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (lifecycle == null) {
if (!Boolean.TRUE.equals(sce.getServletContext().getAttribute(EnhancedListener.ENHANCED_LISTENER_USED_ATTRIBUTE_NAME))) {
// This should never happen
WeldServletLogger.LOG.noServletLifecycleToDestroy();
}
return;
}
super.contextDestroyed(sce);
lifecycle.destroy(sce.getServletContext());
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {
if (lifecycle != null) {
super.requestDestroyed(sre);
}
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
if (lifecycle != null) {
super.requestInitialized(sre);
}
}
@Override
public void sessionCreated(HttpSessionEvent se) {
if (lifecycle != null) {
super.sessionCreated(se);
}
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
if (lifecycle != null) {
super.sessionDestroyed(se);
}
}
@Override
protected ServletListener delegate() {
return lifecycle.getWeldListener();
}
}