org.jboss.weld.environment.servlet.WeldServletLifecycle Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of weld-servlet-shaded Show documentation
Show all versions of weld-servlet-shaded Show documentation
This jar bundles all the bits of Weld and CDI required for running in a Servlet container.
/*
* JBoss, Home of Professional Open Source
* Copyright 2014, 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 static org.jboss.weld.config.ConfigurationKey.BEAN_IDENTIFIER_INDEX_OPTIMIZATION;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.ServiceLoader;
import java.util.Set;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspFactory;
import org.jboss.weld.bean.builtin.BeanManagerProxy;
import org.jboss.weld.bootstrap.WeldBootstrap;
import org.jboss.weld.bootstrap.api.CDI11Bootstrap;
import org.jboss.weld.bootstrap.api.Environments;
import org.jboss.weld.bootstrap.api.TypeDiscoveryConfiguration;
import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive;
import org.jboss.weld.bootstrap.spi.CDI11Deployment;
import org.jboss.weld.bootstrap.spi.EEModuleDescriptor;
import org.jboss.weld.bootstrap.spi.EEModuleDescriptor.ModuleType;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.bootstrap.spi.helpers.EEModuleDescriptorImpl;
import org.jboss.weld.bootstrap.spi.helpers.MetadataImpl;
import org.jboss.weld.configuration.spi.ExternalConfiguration;
import org.jboss.weld.configuration.spi.helpers.ExternalConfigurationBuilder;
import org.jboss.weld.module.web.el.WeldELContextListener;
import org.jboss.weld.environment.ContainerInstance;
import org.jboss.weld.environment.ContainerInstanceFactory;
import org.jboss.weld.environment.deployment.WeldBeanDeploymentArchive;
import org.jboss.weld.environment.deployment.WeldDeployment;
import org.jboss.weld.environment.deployment.WeldResourceLoader;
import org.jboss.weld.environment.deployment.discovery.BeanArchiveHandler;
import org.jboss.weld.environment.deployment.discovery.DiscoveryStrategy;
import org.jboss.weld.environment.deployment.discovery.DiscoveryStrategyFactory;
import org.jboss.weld.environment.deployment.discovery.jandex.Jandex;
import org.jboss.weld.environment.gwtdev.GwtDevHostedModeContainer;
import org.jboss.weld.environment.jetty.JettyContainer;
import org.jboss.weld.environment.logging.CommonLogger;
import org.jboss.weld.environment.servlet.deployment.ServletContextBeanArchiveHandler;
import org.jboss.weld.environment.servlet.deployment.WebAppBeanArchiveScanner;
import org.jboss.weld.environment.servlet.logging.WeldServletLogger;
import org.jboss.weld.environment.servlet.services.ServletResourceInjectionServices;
import org.jboss.weld.environment.tomcat.TomcatContainer;
import org.jboss.weld.environment.undertow.UndertowContainer;
import org.jboss.weld.environment.util.DevelopmentMode;
import org.jboss.weld.environment.util.Reflections;
import org.jboss.weld.injection.spi.ResourceInjectionServices;
import org.jboss.weld.manager.api.WeldManager;
import org.jboss.weld.resources.ManagerObjectFactory;
import org.jboss.weld.resources.WeldClassLoaderResourceLoader;
import org.jboss.weld.resources.spi.ClassFileServices;
import org.jboss.weld.resources.spi.ResourceLoader;
import org.jboss.weld.module.web.servlet.WeldInitialListener;
import org.jboss.weld.servlet.api.ServletListener;
import org.jboss.weld.util.collections.ImmutableSet;
/**
*
* @author Martin Kouba
* @see Listener
* @see EnhancedListener
*/
public class WeldServletLifecycle {
public static final String BEAN_MANAGER_ATTRIBUTE_NAME = WeldServletLifecycle.class.getPackage().getName() + "." + BeanManager.class.getName();
static final String INSTANCE_ATTRIBUTE_NAME = WeldServletLifecycle.class.getPackage().getName() + ".lifecycleInstance";
private static final String EXPRESSION_FACTORY_NAME = "org.jboss.weld.el.ExpressionFactory";
private static final String CONTEXT_PARAM_ARCHIVE_ISOLATION = WeldServletLifecycle.class.getPackage().getName() + ".archive.isolation";
private static final String JANDEX_SERVLET_CONTEXT_BEAN_ARCHIVE_HANDLER = "org.jboss.weld.environment.servlet.deployment.JandexServletContextBeanArchiveHandler";
// This context param is used to activate the development mode
private static final String CONTEXT_PARAM_DEV_MODE = "org.jboss.weld.development";
private static final String JSP_FACTORY_CLASS_NAME = "javax.servlet.jsp.JspFactory";
private Runnable shutdownAction;
private final transient ServletListener weldListener;
private final transient ResourceLoader resourceLoader;
private Container container;
// WELD-1665 Bootstrap might be already performed
private boolean isBootstrapNeeded = true;
private boolean isDevModeEnabled;
WeldServletLifecycle() {
resourceLoader = new WeldResourceLoader();
weldListener = new WeldInitialListener();
}
/**
*
* @param context
* @return true
if initialized properly, false
otherwise
*/
boolean initialize(ServletContext context) {
isDevModeEnabled = Boolean.valueOf(context.getInitParameter(CONTEXT_PARAM_DEV_MODE));
WeldManager manager = (WeldManager) context.getAttribute(BEAN_MANAGER_ATTRIBUTE_NAME);
if (manager != null) {
isBootstrapNeeded = false;
String contextId = BeanManagerProxy.unwrap(manager).getContextId();
context.setInitParameter(org.jboss.weld.Container.CONTEXT_ID_KEY, contextId);
} else {
Object container = context.getAttribute(Listener.CONTAINER_ATTRIBUTE_NAME);
if (container instanceof ContainerInstanceFactory) {
ContainerInstanceFactory factory = (ContainerInstanceFactory) container;
// start the container
ContainerInstance containerInstance = factory.initialize();
container = containerInstance;
// we are in charge of shutdown also
this.shutdownAction = () -> containerInstance.shutdown();
}
if (container instanceof ContainerInstance) {
// the container instance was either passed to us directly or was created in the block above
ContainerInstance containerInstance = (ContainerInstance) container;
manager = BeanManagerProxy.unwrap(containerInstance.getBeanManager());
context.setInitParameter(org.jboss.weld.Container.CONTEXT_ID_KEY, containerInstance.getId());
isBootstrapNeeded = false;
}
}
final CDI11Bootstrap bootstrap = new WeldBootstrap();
if (isBootstrapNeeded) {
final CDI11Deployment deployment = createDeployment(context, bootstrap);
deployment.getServices().add(ExternalConfiguration.class,
new ExternalConfigurationBuilder().add(BEAN_IDENTIFIER_INDEX_OPTIMIZATION.get(), Boolean.FALSE.toString()).build());
if (deployment.getBeanDeploymentArchives().isEmpty()) {
// Skip initialization - there is no bean archive in the deployment
CommonLogger.LOG.initSkippedNoBeanArchiveFound();
return false;
}
ResourceInjectionServices resourceInjectionServices = new ServletResourceInjectionServices() {
};
try {
for (BeanDeploymentArchive archive : deployment.getBeanDeploymentArchives()) {
archive.getServices().add(ResourceInjectionServices.class, resourceInjectionServices);
}
} catch (NoClassDefFoundError e) {
// Support GAE
WeldServletLogger.LOG.resourceInjectionNotAvailable();
}
String id = context.getInitParameter(org.jboss.weld.Container.CONTEXT_ID_KEY);
if (id != null) {
bootstrap.startContainer(id, Environments.SERVLET, deployment);
} else {
bootstrap.startContainer(Environments.SERVLET, deployment);
}
bootstrap.startInitialization();
/*
* Determine the BeanManager used for example for EL resolution - this should work fine as all bean archives share the same classloader. The only
* difference this can make is per-BDA (CDI 1.0 style) enablement of alternatives, interceptors and decorators. Nothing we can do about that.
*
* First try to find the bean archive for WEB-INF/classes. If not found, take the first one available.
*/
for (BeanDeploymentArchive bda : deployment.getBeanDeploymentArchives()) {
if (bda.getId().contains(ManagerObjectFactory.WEB_INF_CLASSES_FILE_PATH) || bda.getId().contains(ManagerObjectFactory.WEB_INF_CLASSES)) {
manager = bootstrap.getManager(bda);
break;
}
}
if (manager == null) {
manager = bootstrap.getManager(deployment.getBeanDeploymentArchives().iterator().next());
}
// Push the manager into the servlet context so we can access in JSF
context.setAttribute(BEAN_MANAGER_ATTRIBUTE_NAME, manager);
}
ContainerContext containerContext = new ContainerContext(context, manager);
StringBuilder dump = new StringBuilder();
Container container = findContainer(containerContext, dump);
if (container == null) {
WeldServletLogger.LOG.noSupportedServletContainerDetected();
WeldServletLogger.LOG.debugv("Exception dump from Container lookup: {0}", dump);
} else {
container.initialize(containerContext);
this.container = container;
}
if (Reflections.isClassLoadable(WeldClassLoaderResourceLoader.INSTANCE, JSP_FACTORY_CLASS_NAME) && JspFactory.getDefaultFactory() != null) {
JspApplicationContext jspApplicationContext = JspFactory.getDefaultFactory().getJspApplicationContext(context);
// Register the ELResolver with JSP
jspApplicationContext.addELResolver(manager.getELResolver());
// Register ELContextListener with JSP
try {
jspApplicationContext.addELContextListener(new WeldELContextListener());
} catch (Exception e) {
throw WeldServletLogger.LOG.errorLoadingWeldELContextListener(e);
}
// Push the wrapped expression factory into the servlet context so that Tomcat or Jetty can hook it in using a container code
context.setAttribute(EXPRESSION_FACTORY_NAME, manager.wrapExpressionFactory(jspApplicationContext.getExpressionFactory()));
}
if (isBootstrapNeeded) {
bootstrap.deployBeans().validateBeans().endInitialization();
if (isDevModeEnabled) {
FilterRegistration.Dynamic filterDynamic = context.addFilter("Weld Probe Filter", DevelopmentMode.PROBE_FILTER_CLASS_NAME);
filterDynamic.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE), true, "/*");
}
this.shutdownAction = () -> bootstrap.shutdown();
}
return true;
}
void destroy(ServletContext context) {
if (shutdownAction != null) {
// Shutdown only if bootstrap not skipped
shutdownAction.run();
}
if (container != null) {
container.destroy(new ContainerContext(context, null));
}
}
/**
*
* @return the original Weld listener all notifications should be delegated to
*/
ServletListener getWeldListener() {
return weldListener;
}
/**
* Create servlet deployment.
*
* Can be overridden with custom servlet deployment. e.g. exact resources listing in restricted env like GAE
*
* @param context the servlet context
* @param bootstrap the bootstrap
* @return new servlet deployment
*/
protected CDI11Deployment createDeployment(ServletContext context, CDI11Bootstrap bootstrap) {
ImmutableSet.Builder> extensionsBuilder = ImmutableSet.builder();
extensionsBuilder.addAll(bootstrap.loadExtensions(WeldResourceLoader.getClassLoader()));
if (isDevModeEnabled) {
extensionsBuilder.add(new MetadataImpl(DevelopmentMode.getProbeExtension(resourceLoader), "N/A"));
}
final Iterable> extensions = extensionsBuilder.build();
final TypeDiscoveryConfiguration typeDiscoveryConfiguration = bootstrap.startExtensions(extensions);
final EEModuleDescriptor eeModule = new EEModuleDescriptorImpl(context.getContextPath(), ModuleType.WEB);
final DiscoveryStrategy strategy = DiscoveryStrategyFactory.create(resourceLoader, bootstrap, typeDiscoveryConfiguration.getKnownBeanDefiningAnnotations(),
Boolean.parseBoolean(context.getInitParameter(Jandex.DISABLE_JANDEX_DISCOVERY_STRATEGY)));
if (Jandex.isJandexAvailable(resourceLoader)) {
try {
Class extends BeanArchiveHandler> handlerClass = Reflections.loadClass(resourceLoader, JANDEX_SERVLET_CONTEXT_BEAN_ARCHIVE_HANDLER);
strategy.registerHandler((SecurityActions.newConstructorInstance(handlerClass, new Class>[] { ServletContext.class }, context)));
} catch (Exception e) {
throw CommonLogger.LOG.unableToInstantiate(JANDEX_SERVLET_CONTEXT_BEAN_ARCHIVE_HANDLER, Arrays.toString(new Object[] { context }), e);
}
} else {
strategy.registerHandler(new ServletContextBeanArchiveHandler(context));
}
strategy.setScanner(new WebAppBeanArchiveScanner(resourceLoader, bootstrap, context));
Set beanDeploymentArchives = strategy.performDiscovery();
String isolation = context.getInitParameter(CONTEXT_PARAM_ARCHIVE_ISOLATION);
if (isolation == null || Boolean.valueOf(isolation)) {
CommonLogger.LOG.archiveIsolationEnabled();
} else {
CommonLogger.LOG.archiveIsolationDisabled();
Set flatDeployment = new HashSet();
flatDeployment.add(WeldBeanDeploymentArchive.merge(bootstrap, beanDeploymentArchives));
beanDeploymentArchives = flatDeployment;
}
for (BeanDeploymentArchive archive : beanDeploymentArchives) {
archive.getServices().add(EEModuleDescriptor.class, eeModule);
}
CDI11Deployment deployment = new WeldDeployment(resourceLoader, bootstrap, beanDeploymentArchives, extensions) {
@Override
protected WeldBeanDeploymentArchive createAdditionalBeanDeploymentArchive() {
WeldBeanDeploymentArchive archive = super.createAdditionalBeanDeploymentArchive();
archive.getServices().add(EEModuleDescriptor.class, eeModule);
return archive;
}
};
if (strategy.getClassFileServices() != null) {
deployment.getServices().add(ClassFileServices.class, strategy.getClassFileServices());
}
return deployment;
}
/**
* Find container env.
*
* @param ctx the container context
* @param dump the exception dump
* @return valid container or null
*/
protected Container findContainer(ContainerContext ctx, StringBuilder dump) {
Container container = null;
// 1. Custom container class
String containerClassName = ctx.getServletContext().getInitParameter(Container.CONTEXT_PARAM_CONTAINER_CLASS);
if (containerClassName != null) {
try {
Class containerClass = Reflections.classForName(resourceLoader, containerClassName);
container = SecurityActions.newInstance(containerClass);
WeldServletLogger.LOG.containerDetectionSkipped(containerClassName);
} catch (Exception e) {
WeldServletLogger.LOG.unableToInstantiateCustomContainerClass(containerClassName);
WeldServletLogger.LOG.catchingDebug(e);
}
}
if (container == null) {
// 2. Service providers
Iterable extContainers = ServiceLoader.load(Container.class, getClass().getClassLoader());
container = checkContainers(ctx, dump, extContainers);
if (container == null) {
// 3. Built-in containers in predefined order
container = checkContainers(ctx, dump,
Arrays.asList(TomcatContainer.INSTANCE, JettyContainer.INSTANCE, UndertowContainer.INSTANCE, GwtDevHostedModeContainer.INSTANCE));
}
}
return container;
}
protected Container checkContainers(ContainerContext containerContext, StringBuilder dump, Iterable containers) {
for (Container container : containers) {
try {
if (container.touch(resourceLoader, containerContext)) {
return container;
}
} catch (Throwable t) {
dump.append(container).append("->").append(t.getMessage()).append("\n");
}
}
return null;
}
}