org.jboss.weld.environment.se.Weld Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2009, Red Hat, Inc. and/or its affiliates, 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.se;
import static org.jboss.weld.environment.util.URLUtils.JAR_URL_SEPARATOR;
import static org.jboss.weld.environment.util.URLUtils.PROCOTOL_FILE;
import static org.jboss.weld.environment.util.URLUtils.PROCOTOL_JAR;
import static org.jboss.weld.environment.util.URLUtils.PROTOCOL_FILE_PART;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.annotation.Priority;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.UnsatisfiedResolutionException;
import javax.enterprise.inject.Vetoed;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.Extension;
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.Service;
import org.jboss.weld.bootstrap.api.SingletonProvider;
import org.jboss.weld.bootstrap.api.TypeDiscoveryConfiguration;
import org.jboss.weld.bootstrap.api.helpers.RegistrySingletonProvider;
import org.jboss.weld.bootstrap.spi.BeanDeploymentArchive;
import org.jboss.weld.bootstrap.spi.BeanDiscoveryMode;
import org.jboss.weld.bootstrap.spi.BeansXml;
import org.jboss.weld.bootstrap.spi.Deployment;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.bootstrap.spi.helpers.MetadataImpl;
import org.jboss.weld.config.ConfigurationKey;
import org.jboss.weld.configuration.spi.ExternalConfiguration;
import org.jboss.weld.configuration.spi.helpers.ExternalConfigurationBuilder;
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.ClassPathBeanArchiveScanner;
import org.jboss.weld.environment.deployment.discovery.DiscoveryStrategy;
import org.jboss.weld.environment.deployment.discovery.DiscoveryStrategyFactory;
import org.jboss.weld.environment.logging.CommonLogger;
import org.jboss.weld.environment.se.contexts.ThreadScoped;
import org.jboss.weld.environment.se.logging.WeldSELogger;
import org.jboss.weld.environment.util.BeanArchives;
import org.jboss.weld.environment.util.DevelopmentMode;
import org.jboss.weld.environment.util.Files;
import org.jboss.weld.metadata.BeansXmlImpl;
import org.jboss.weld.resources.ClassLoaderResourceLoader;
import org.jboss.weld.resources.spi.ClassFileServices;
import org.jboss.weld.resources.spi.ResourceLoader;
import org.jboss.weld.security.GetClassLoaderAction;
import org.jboss.weld.security.GetSystemPropertyAction;
import org.jboss.weld.util.Preconditions;
import org.jboss.weld.util.ServiceLoader;
import org.jboss.weld.util.Services;
import org.jboss.weld.util.collections.ImmutableList;
import org.jboss.weld.util.collections.ImmutableSet;
import org.jboss.weld.util.collections.Iterables;
import org.jboss.weld.util.collections.Multimap;
import org.jboss.weld.util.collections.WeldCollections;
/**
*
* This builder is a preferred method of booting Weld SE container.
*
*
*
* Typical usage looks like this:
*
*
*
* WeldContainer container = new Weld().initialize();
* container.select(Foo.class).get();
* container.event().select(Bar.class).fire(new Bar());
* container.shutdown();
*
*
*
* The {@link WeldContainer} implements AutoCloseable:
*
*
*
* try (WeldContainer container = new Weld().initialize()) {
* container.select(Foo.class).get();
* }
*
*
*
* By default, the discovery is enabled so that all beans from all discovered bean archives are considered. However, it's possible to define a "synthetic" bean
* archive, or the set of bean classes and enablement respectively:
*
*
*
* WeldContainer container = new Weld().beanClasses(Foo.class, Bar.class).alternatives(Bar.class).initialize()) {
*
*
*
* Moreover, it's also possible to disable the discovery completely so that only the "synthetic" bean archive is considered:
*
*
*
* WeldContainer container = new Weld().disableDiscovery().beanClasses(Foo.class, Bar.class).initialize()) {
*
*
*
*
* In the same manner, it is possible to explicitly declare interceptors, decorators, extensions and Weld-specific options (such as relaxed construction) using
* the builder.
*
*
*
* Weld builder = new Weld()
* .disableDiscovery()
* .packages(Main.class, Utils.class)
* .interceptors(TransactionalInterceptor.class)
* .property("org.jboss.weld.construction.relaxed", true);
* WeldContainer container = builder.initialize();
*
*
*
* The builder is reusable which means that it's possible to initialize multiple Weld containers with one builder. However, note that containers must have a
* unique identifier assigned when running multiple Weld instances at the same time.
*
*
* @author Peter Royle
* @author Pete Muir
* @author Ales Justin
* @author Martin Kouba
* @see WeldContainer
*/
@Vetoed
public class Weld implements ContainerInstanceFactory {
/**
* By default, bean archive isolation is enabled. If set to false, Weld will use a "flat" deployment structure - all bean classes share the same bean
* archive and all beans.xml descriptors are automatically merged into one.
*
* This key can be also used through {@link #property(String, Object)}.
*/
public static final String ARCHIVE_ISOLATION_SYSTEM_PROPERTY = "org.jboss.weld.se.archive.isolation";
/**
* By default, the development mode is disabled. If set to true, the development mode is activated
*
* This key can be also used through {@link #property(String, Object)}.
*/
public static final String DEV_MODE_SYSTEM_PROPERTY = "org.jboss.weld.development";
/**
* By default, Weld automatically registers shutdown hook during initialization. If set to false, the registration of a shutdown hook is skipped.
*
* This key can be also used through {@link #property(String, Object)}.
*/
public static final String SHUTDOWN_HOOK_SYSTEM_PROPERTY = "org.jboss.weld.se.shutdownHook";
/**
* By default, Weld SE does not support implicit bean archives without beans.xml. If set to true, Weld scans the class path entries and implicit bean
* archives which don't contain a beans.xml file are also supported.
*
* This key can be also used through {@link #property(String, Object)}.
*/
public static final String SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY = "org.jboss.weld.se.scan.classpath.entries";
private static final String SYNTHETIC_LOCATION_PREFIX = "synthetic:";
static {
if (!(SingletonProvider.instance() instanceof RegistrySingletonProvider)) {
// make sure RegistrySingletonProvider is used (required for supporting multiple parallel Weld instances)
SingletonProvider.reset();
SingletonProvider.initialize(new RegistrySingletonProvider());
}
}
private final Map initializedContainers;
private String containerId;
private boolean discoveryEnabled = true;
private final Set beanClasses;
private final List> selectedAlternatives;
private final List> selectedAlternativeStereotypes;
private final List> enabledInterceptors;
private final List> enabledDecorators;
private final Set> extensions;
private final Map properties;
private final Set packages;
private ResourceLoader resourceLoader;
private final Map, Service> additionalServices;
public Weld() {
this(null);
}
/**
*
* @param containerId The container identifier
* @see Weld#containerId(String)
*/
public Weld(String containerId) {
this.containerId = containerId;
this.initializedContainers = new HashMap();
this.beanClasses = new HashSet();
this.selectedAlternatives = new ArrayList>();
this.selectedAlternativeStereotypes = new ArrayList>();
this.enabledInterceptors = new ArrayList>();
this.enabledDecorators = new ArrayList>();
this.extensions = new HashSet>();
this.properties = new HashMap();
this.packages = new HashSet();
this.resourceLoader = new WeldResourceLoader();
this.additionalServices = new HashMap<>();
}
/**
* Containers must have a unique identifier assigned when running multiple Weld instances at the same time.
*
* @param containerId
* @return self
*/
public Weld containerId(String containerId) {
this.containerId = containerId;
return this;
}
/**
*
* @return a container identifier
* @see #containerId(String)
*/
public String getContainerId() {
return containerId;
}
/**
* Define the set of bean classes for the synthetic bean archive.
*
* @param classes
* @return self
*/
public Weld beanClasses(Class>... classes) {
beanClasses.clear();
for (Class> beanClass : classes) {
addBeanClass(beanClass);
}
return this;
}
/**
* Add a bean class to the set of bean classes for the synthetic bean archive.
*
* @param beanClass
* @return self
*/
public Weld addBeanClass(Class> beanClass) {
beanClasses.add(beanClass.getName());
return this;
}
/**
* All classes from the packages of the specified classes will be added to the set of bean classes for the synthetic bean archive.
*
*
* Note that the scanning possibilities are limited. Therefore, only directories and jar files from the filesystem are supported.
*
*
*
* Scanning may also have negative impact on bootstrap performance.
*
*
* @param classes
* @return self
*/
public Weld packages(Class>... packageClasses) {
packages.clear();
addPackages(false, packageClasses);
return this;
}
/**
* Packages of the specified classes will be scanned and found classes will be added to the set of bean classes for the synthetic bean archive.
*
* @param scanRecursively
* @param packageClasses
* @return self
*/
public Weld addPackages(boolean scanRecursively, Class>... packageClasses) {
for (Class> packageClass : packageClasses) {
addPackage(scanRecursively, packageClass);
}
return this;
}
/**
* A package of the specified class will be scanned and found classes will be added to the set of bean classes for the synthetic bean archive.
*
* @param scanRecursively
* @param packageClass
* @return self
*/
public Weld addPackage(boolean scanRecursively, Class> packageClass) {
packages.add(new PackInfo(packageClass, scanRecursively));
return this;
}
/**
* Provided Packages will be scanned and found classes will be added to the set of bean classes for the synthetic bean archive.
*
* @param packages Packages to be scanned
* @return self
*/
public Weld addPackages(Package... packages){
addPackages(false, packages);
return this;
}
/**
* Provided Packages will be scanned and found classes will be added to the set of bean classes for the synthetic bean archive.
* Also allows to choose whether or not the scanning should be recursive.
*
* @param scanRecursively indicates whether scanning process should be recursive
* @param packages Packages to be scanned
* @return self
*/
public Weld addPackages(boolean scanRecursively, Package... packages){
for (Package pack : packages) {
this.packages.add(new PackInfo(pack, scanRecursively));
}
return this;
}
/**
* Define the set of extensions.
*
* @param extensions
* @return self
*/
public Weld extensions(Extension... extensions) {
this.extensions.clear();
for (Extension extension : extensions) {
addExtension(extension);
}
return this;
}
/**
* Add an extension to the set of extensions.
*
* @param extension an extension
*/
public Weld addExtension(Extension extension) {
extensions.add(new MetadataImpl(extension, SYNTHETIC_LOCATION_PREFIX + extension.getClass().getName()));
return this;
}
/**
* Attempts to initialize the classes as extensions and add them to the set of extensions.
*
* @param extensionClasses Classes to be initialized as extensions and added to the set of extensions
* @return self
*/
@SuppressWarnings("unchecked")
public Weld addExtensions(Class extends Extension>... extensionClasses) {
for (Class extends Extension> extensionClass : extensionClasses) {
try {
Extension extension = SecurityActions.newInstance(extensionClass);
addExtension(extension);
} catch (Exception ex) {
CommonLogger.LOG.unableToInstantiate(extensionClass, new Object[] {}, ex);
}
}
return this;
}
/**
* Enable interceptors for the synthetic bean archive, all previous values are removed.
*
* This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the
* beans.xml
descriptor.
*
* @param interceptorClasses
* @return self
*/
public Weld interceptors(Class>... interceptorClasses) {
enabledInterceptors.clear();
for (Class> interceptorClass : interceptorClasses) {
addInterceptor(interceptorClass);
}
return this;
}
/**
* Add interceptor classes to the list of enabled interceptors for the synthetic bean archive.
*
* This method does not add any class to the set of bean classes of the synthetic bean archive.
*
* @param interceptorClasses interceptors to enable
* @return self
*/
public Weld enableInterceptors(Class>... interceptorClasses) {
for (Class> clazz : interceptorClasses) {
addInterceptor(clazz);
}
return this;
}
/**
* Add an interceptor class to the list of enabled interceptors for the synthetic bean archive.
*
* This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the
* beans.xml
descriptor.
*
* @param interceptorClass
* @return self
*/
public Weld addInterceptor(Class> interceptorClass) {
enabledInterceptors.add(syntheticMetadata(interceptorClass));
return this;
}
/**
* Enable decorators for the synthetic bean archive, all previous values are removed.
*
* This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the
* beans.xml
descriptor.
*
* @param decoratorClasses
* @return self
*/
public Weld decorators(Class>... decoratorClasses) {
enabledDecorators.clear();
for (Class> decoratorClass : decoratorClasses) {
addDecorator(decoratorClass);
}
return this;
}
/**
* Add decorator classes to the list of enabled decorators for the synthetic bean archive.
*
* This method does not add any class to the set of bean classes of the synthetic bean archive.
*
* @param decoratorClasses decorators to enable
* @return self
*/
public Weld enableDecorators(Class>... decoratorClasses) {
for (Class> clazz : decoratorClasses) {
addDecorator(clazz);
}
return this;
}
/**
* Add a decorator class to the list of enabled decorators for the synthetic bean archive.
*
* This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the
* beans.xml
descriptor.
*
* @param decoratorClass
* @return self
*/
public Weld addDecorator(Class> decoratorClass) {
enabledDecorators.add(syntheticMetadata(decoratorClass));
return this;
}
/**
* Select alternatives for the synthetic bean archive, all previous values are removed.
*
* This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the
* beans.xml
descriptor.
*
* @param alternativeClasses
* @return self
*/
public Weld alternatives(Class>... alternativeClasses) {
selectedAlternatives.clear();
for (Class> alternativeClass : alternativeClasses) {
addAlternative(alternativeClass);
}
return this;
}
/**
* Add an alternative class to the list of selected alternatives for a synthetic bean archive.
*
* This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the
* beans.xml
descriptor.
*
* @param alternativeClass
* @return self
*/
public Weld addAlternative(Class> alternativeClass) {
selectedAlternatives.add(syntheticMetadata(alternativeClass));
return this;
}
/**
* Add alternatives classes to the list of selected alternatives for the synthetic bean archive.
*
* This method does not add any class to the set of bean classes of the synthetic bean archive.
*
* @param alternativeClasses classes of the alternatives to select
* @return self
*/
public Weld selectAlternatives(Class>... alternativeClasses) {
for (Class> clazz : alternativeClasses) {
addAlternative(clazz);
}
return this;
}
/**
* Select alternative stereotypes for the synthetic bean archive, all previous values are removed.
*
* This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the
* beans.xml
descriptor.
*
* @param alternativeStereotypeClasses
* @return self
*/
@SafeVarargs
public final Weld alternativeStereotypes(Class extends Annotation>... alternativeStereotypeClasses) {
selectedAlternativeStereotypes.clear();
for (Class extends Annotation> alternativeStereotypeClass : alternativeStereotypeClasses) {
addAlternativeStereotype(alternativeStereotypeClass);
}
return this;
}
/**
* Add an alternative stereotype class to the list of selected alternative stereotypes for a synthetic bean archive.
*
* This method does not add any class to the set of bean classes for the synthetic bean archive. It's purpose is solely to compensate the absence of the
* beans.xml
descriptor.
*
* @param alternativeStereotypeClass
* @return self
*/
public Weld addAlternativeStereotype(Class extends Annotation> alternativeStereotypeClass) {
selectedAlternativeStereotypes.add(syntheticMetadata(alternativeStereotypeClass));
return this;
}
/**
* Add alternative stereotype classes to the list of selected alternative stereotypes for the synthetic bean archive.
*
* This method does not add any class to the set of bean classes of the synthetic bean archive.
*
* @param alternativeStereotypeClasses alternatives stereotypes to select
* @return self
*/
@SuppressWarnings("unchecked")
public Weld selectAlternativeStereotypes(Class extends Annotation>... alternativeStereotypeClasses) {
for (Class extends Annotation> clazz : alternativeStereotypeClasses) {
addAlternativeStereotype(clazz);
}
return this;
}
/**
* Set the configuration property.
*
* @param key
* @param value
* @return self
* @see #ARCHIVE_ISOLATION_SYSTEM_PROPERTY
* @see #SHUTDOWN_HOOK_SYSTEM_PROPERTY
* @see #DEV_MODE_SYSTEM_PROPERTY
* @see ConfigurationKey
*/
public Weld property(String key, Object value) {
properties.put(key, value);
return this;
}
/**
* Replaces previously set configuration setProperties with those provided in a Map
*
* @param propertiesMap a map containing configuration setProperties to be set
* @return self
* @see #ARCHIVE_ISOLATION_SYSTEM_PROPERTY
* @see #SHUTDOWN_HOOK_SYSTEM_PROPERTY
* @see #DEV_MODE_SYSTEM_PROPERTY
* @see ConfigurationKey
*/
public Weld setProperties(Map propertiesMap) {
properties.clear();
properties.putAll(propertiesMap);
return this;
}
/**
* Register per-deployment services which are shared across the entire application.
*
* Weld uses services to communicate with its environment, e.g. {@link org.jboss.weld.manager.api.ExecutorServices} or
* {@link org.jboss.weld.transaction.spi.TransactionServices}.
*
*
* Service implementation may specify their priority using {@link Priority}. Services with higher priority have precedence. Services that do not specify
* priority have the default priority of 4500.
*
*
* @param services
* @return self
* @see Service
*/
public Weld addServices(Service... services) {
for (Service service : services) {
for (Class extends Service> serviceInterface : Services.identifyServiceInterfaces(service.getClass(), new HashSet>())) {
additionalServices.put(serviceInterface, service);
}
}
return this;
}
/**
* Reset the synthetic bean archive (bean classes and enablement), explicitly added extensions and services.
*
* @return self
*/
public Weld reset() {
beanClasses.clear();
packages.clear();
selectedAlternatives.clear();
selectedAlternativeStereotypes.clear();
enabledInterceptors.clear();
enabledDecorators.clear();
extensions.clear();
additionalServices.clear();
return this;
}
/**
* Reset all the state, except for initialized containers.
*
* @return self
* @see Weld#reset()
*/
public Weld resetAll() {
reset();
properties.clear();
enableDiscovery();
containerId(null);
return this;
}
/**
*
* @return self
* @see #disableDiscovery()
*/
public Weld enableDiscovery() {
this.discoveryEnabled = true;
return this;
}
/**
* By default, the discovery is enabled. However, it's possible to disable the discovery completely so that only the "synthetic" bean archive is considered.
*
* @return self
*/
public Weld disableDiscovery() {
this.discoveryEnabled = false;
return this;
}
/**
*
* @return true
if the discovery is enabled, false
otherwise
* @see #disableDiscovery()
*/
public boolean isDiscoveryEnabled() {
return discoveryEnabled;
}
/**
* Bootstraps a new Weld SE container with the current container id (generated value if not set through {@link #containerId(String)}).
*
* The container must be shut down properly when an application is stopped. Applications are encouraged to use the try-with-resources statement or invoke
* {@link WeldContainer#shutdown()} explicitly.
*
* However, a shutdown hook is also registered during initialization so that all running containers are shut down automatically when a program exits or VM
* is terminated. This means that it's not necessary to implement the shutdown logic in a class where a main method is used to start the container.
*
* @return the Weld container
* @see #enableDiscovery()
* @see WeldContainer#shutdown()
*/
public WeldContainer initialize() {
// If also building a synthetic bean archive or the implicit scan is enabled, the check for beans.xml is not necessary
if (!isSyntheticBeanArchiveRequired() && !isEnabled(SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY, false)
&& resourceLoader.getResource(WeldDeployment.BEANS_XML) == null) {
throw CommonLogger.LOG.missingBeansXml();
}
final CDI11Bootstrap bootstrap = new WeldBootstrap();
final Deployment deployment = createDeployment(resourceLoader, bootstrap);
final ExternalConfigurationBuilder configurationBuilder = new ExternalConfigurationBuilder()
// weld-se uses relaxed construction by default
.add(ConfigurationKey.RELAXED_CONSTRUCTION.get(), true);
for (Entry property : properties.entrySet()) {
String key = property.getKey();
if (SHUTDOWN_HOOK_SYSTEM_PROPERTY.equals(key) || ARCHIVE_ISOLATION_SYSTEM_PROPERTY.equals(key) || DEV_MODE_SYSTEM_PROPERTY.equals(key)
|| SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY.equals(key)) {
continue;
}
configurationBuilder.add(key, property.getValue());
}
deployment.getServices().add(ExternalConfiguration.class, configurationBuilder.build());
final String containerId = this.containerId != null ? this.containerId : UUID.randomUUID().toString();
bootstrap.startContainer(containerId, Environments.SE, deployment);
final WeldContainer weldContainer = WeldContainer.startInitialization(containerId, deployment, bootstrap);
try {
bootstrap.startInitialization();
bootstrap.deployBeans();
bootstrap.validateBeans();
bootstrap.endInitialization();
WeldContainer.endInitialization(weldContainer, isEnabled(SHUTDOWN_HOOK_SYSTEM_PROPERTY, true));
initializedContainers.put(containerId, weldContainer);
} catch (Throwable e) {
// Discard the container if a bootstrap problem occurs, e.g. validation error
WeldContainer.discard(weldContainer.getId());
throw e;
}
return weldContainer;
}
/**
* Shuts down all the containers initialized by this builder.
*/
public void shutdown() {
if (!initializedContainers.isEmpty()) {
for (WeldContainer container : initializedContainers.values()) {
container.shutdown();
}
}
}
/**
* Set a {@link ClassLoader}. The given {@link ClassLoader} will be scanned automatically for bean archives if scanning is enabled.
*
* @param classLoader
* @return self
*/
public Weld setClassLoader(ClassLoader classLoader) {
Preconditions.checkNotNull(classLoader);
resourceLoader = new ClassLoaderResourceLoader(classLoader);
return this;
}
/**
* Set a {@link ResourceLoader} used to scan the application for bean archives. If you only want to use a specific {@link ClassLoader} for scanning, use
* {@link #setClassLoader(ClassLoader)} instead.
*
* @param resourceLoader
* @return self
* @see #isDiscoveryEnabled()
*/
public Weld setResourceLoader(ResourceLoader resourceLoader) {
Preconditions.checkNotNull(resourceLoader);
this.resourceLoader = resourceLoader;
return this;
}
/**
*
* Extensions to Weld SE can subclass and override this method to customize the deployment before weld boots up. For example, to add a custom
* ResourceLoader, you would subclass Weld like so:
*
*
*
* public class MyWeld extends Weld {
* protected Deployment createDeployment(ResourceLoader resourceLoader, CDI11Bootstrap bootstrap) {
* return super.createDeployment(new MyResourceLoader(), bootstrap);
* }
* }
*
*
*
* This could then be used as normal:
*
*
*
* WeldContainer container = new MyWeld().initialize();
*
*
* @param resourceLoader
* @param bootstrap
*/
protected Deployment createDeployment(ResourceLoader resourceLoader, CDI11Bootstrap bootstrap) {
final Iterable> extensions = getExtensions();
final TypeDiscoveryConfiguration typeDiscoveryConfiguration = bootstrap.startExtensions(extensions);
final Deployment deployment;
final Set beanDeploymentArchives = new HashSet();
final Map, Service> additionalServices = new HashMap<>(this.additionalServices);
if (discoveryEnabled) {
DiscoveryStrategy strategy = DiscoveryStrategyFactory.create(resourceLoader, bootstrap,
ImmutableSet.> builder().addAll(typeDiscoveryConfiguration.getKnownBeanDefiningAnnotations())
// Add ThreadScoped manually as Weld SE doesn't support implicit bean archives without beans.xml
.add(ThreadScoped.class).build());
if (isEnabled(SCAN_CLASSPATH_ENTRIES_SYSTEM_PROPERTY, false)) {
strategy.setScanner(new ClassPathBeanArchiveScanner(bootstrap));
}
beanDeploymentArchives.addAll(strategy.performDiscovery());
ClassFileServices classFileServices = strategy.getClassFileServices();
if (classFileServices != null) {
additionalServices.put(ClassFileServices.class, classFileServices);
}
}
if (isSyntheticBeanArchiveRequired()) {
ImmutableSet.Builder beanClassesBuilder = ImmutableSet.builder();
beanClassesBuilder.addAll(beanClasses);
beanClassesBuilder.addAll(scanPackages());
WeldBeanDeploymentArchive syntheticBeanArchive = new WeldBeanDeploymentArchive(WeldDeployment.SYNTHETIC_BDA_ID, beanClassesBuilder.build(),
buildSyntheticBeansXml());
beanDeploymentArchives.add(syntheticBeanArchive);
}
if (beanDeploymentArchives.isEmpty()) {
throw WeldSELogger.LOG.weldContainerCannotBeInitializedNoBeanArchivesFound();
}
Multimap problems = BeanArchives.findBeanClassesDeployedInMultipleBeanArchives(beanDeploymentArchives);
if (!problems.isEmpty()) {
// Right now, we only log a warning for each bean class deployed in multiple bean archives
for (Entry> entry : problems.entrySet()) {
WeldSELogger.LOG.beanClassDeployedInMultipleBeanArchives(entry.getKey(), WeldCollections.toMultiRowString(entry.getValue()));
}
}
if (isEnabled(ARCHIVE_ISOLATION_SYSTEM_PROPERTY, true)) {
deployment = new WeldDeployment(resourceLoader, bootstrap, beanDeploymentArchives, extensions);
CommonLogger.LOG.archiveIsolationEnabled();
} else {
Set flatDeployment = new HashSet();
flatDeployment.add(WeldBeanDeploymentArchive.merge(bootstrap, beanDeploymentArchives));
deployment = new WeldDeployment(resourceLoader, bootstrap, flatDeployment, extensions);
CommonLogger.LOG.archiveIsolationDisabled();
}
// Register additional services if a service with higher priority not present
for (Entry, Service> entry : additionalServices.entrySet()) {
Services.put(deployment.getServices(), entry.getKey(), entry.getValue());
}
return deployment;
}
/**
* Utility method allowing managed instances of beans to provide entry points for non-managed beans (such as {@link WeldContainer}). Should only called once
* Weld has finished booting.
*
* @param manager the BeanManager to use to access the managed instance
* @param type the type of the Bean
* @param bindings the bean's qualifiers
* @return a managed instance of the bean
* @throws IllegalArgumentException if the given type represents a type variable
* @throws IllegalArgumentException if two instances of the same qualifier type are given
* @throws IllegalArgumentException if an instance of an annotation that is not a qualifier type is given
* @throws UnsatisfiedResolutionException if no beans can be resolved * @throws AmbiguousResolutionException if the ambiguous dependency resolution rules
* fail
* @throws IllegalArgumentException if the given type is not a bean type of the given bean
*/
protected T getInstanceByType(BeanManager manager, Class type, Annotation... bindings) {
final Bean> bean = manager.resolve(manager.getBeans(type, bindings));
if (bean == null) {
throw CommonLogger.LOG.unableToResolveBean(type, Arrays.asList(bindings));
}
CreationalContext> cc = manager.createCreationalContext(bean);
return type.cast(manager.getReference(bean, type, cc));
}
private boolean isSyntheticBeanArchiveRequired() {
return !beanClasses.isEmpty() || !packages.isEmpty();
}
private Iterable> getExtensions() {
Set> result = new HashSet>();
if (discoveryEnabled) {
Iterables.addAll(result, loadExtensions(resourceLoader));
}
if (!extensions.isEmpty()) {
result.addAll(extensions);
}
// Ensure that WeldSEBeanRegistrant is present
WeldSEBeanRegistrant weldSEBeanRegistrant = null;
for (Metadata metadata : result) {
if (metadata.getValue().getClass().getName().equals(WeldSEBeanRegistrant.class.getName())) {
weldSEBeanRegistrant = (WeldSEBeanRegistrant) metadata.getValue();
break;
}
}
if (weldSEBeanRegistrant == null) {
try {
weldSEBeanRegistrant = SecurityActions.newInstance(WeldSEBeanRegistrant.class);
result.add(new MetadataImpl(weldSEBeanRegistrant, SYNTHETIC_LOCATION_PREFIX + WeldSEBeanRegistrant.class.getName()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if (isEnabled(DEV_MODE_SYSTEM_PROPERTY, false)) {
// The development mode is enabled - register the Probe extension
result.add(new MetadataImpl(DevelopmentMode.getProbeExtension(resourceLoader), "N/A"));
}
return result;
}
private Iterable> loadExtensions(ResourceLoader resourceLoader) {
return ServiceLoader.load(Extension.class, resourceLoader);
}
private BeansXml buildSyntheticBeansXml() {
return new BeansXmlImpl(ImmutableList.copyOf(selectedAlternatives), ImmutableList.copyOf(selectedAlternativeStereotypes),
ImmutableList.copyOf(enabledDecorators), ImmutableList.copyOf(enabledInterceptors), null, null, BeanDiscoveryMode.ALL, null, false);
}
private MetadataImpl syntheticMetadata(Class> clazz) {
return new MetadataImpl(clazz.getName(), SYNTHETIC_LOCATION_PREFIX + clazz.getName());
}
private Set scanPackages() {
if (packages.isEmpty()) {
return Collections.emptySet();
}
Set foundClasses = new HashSet();
for (PackInfo packInfo : packages) {
String packName = packInfo.getPackName();
URL resourceUrl = packInfo.getResourceUrl(resourceLoader);
if (resourceUrl != null) {
WeldSELogger.LOG.scanningPackage(packName, resourceUrl);
try {
URI resourceUri = resourceUrl.toURI();
if (PROCOTOL_FILE.equals(resourceUrl.getProtocol())) {
// Get the package directory, e.g. "file:///home/weld/org/jboss
if (packInfo.getPackClassName() == null) {
// this branch handles the case when we used Package instead of Class
handleDir(new File(resourceUri), packInfo.isScanRecursively(), packName, foundClasses);
}else {
handleDir(new File(resourceUri).getParentFile(), packInfo.isScanRecursively(), packName, foundClasses);
}
} else if (PROCOTOL_JAR.equals(resourceUrl.getProtocol())) {
handleJar(resourceUri, packInfo.isScanRecursively(), packName, foundClasses);
} else {
WeldSELogger.LOG.resourceUrlProtocolNotSupported(resourceUrl);
}
} catch (URISyntaxException e) {
CommonLogger.LOG.couldNotReadResource(resourceUrl, e);
}
} else {
WeldSELogger.LOG.packageNotFound(packName);
}
}
return foundClasses;
}
private void handleDir(File packDir, boolean scanRecursively, String packName, Set foundClasses) {
if (packDir != null && packDir.exists() && packDir.canRead()) {
for (File file : packDir.listFiles()) {
if (file.isFile()) {
if (file.canRead() && Files.isClass(file.getName())) {
foundClasses.add(Files.filenameToClassname(packName + "." + file.getName()));
}
}
if (file.isDirectory() && scanRecursively) {
handleDir(file, scanRecursively, packName + "." + file.getName(), foundClasses);
}
}
}
}
private void handleJar(URI resourceUri, boolean scanRecursively, String packName, Set foundClasses) {
// Currently we only support jar:file
if (resourceUri.getSchemeSpecificPart().startsWith(PROCOTOL_FILE)) {
// Get the JAR file path, e.g. "jar:file:/home/duke/duke.jar!/com/foo/Bar" becomes "/home/duke/duke.jar"
String path = resourceUri.getSchemeSpecificPart().substring(PROTOCOL_FILE_PART.length());
if (path.lastIndexOf(JAR_URL_SEPARATOR) > 0) {
path = path.substring(0, path.lastIndexOf(JAR_URL_SEPARATOR));
}
JarFile jar = null;
String packNamePath = packName.replace('.', '/');
int expectedPartsLength = splitBySlash(packNamePath).length + 1;
try {
jar = new JarFile(new File(path));
Enumeration entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (!entry.getName().endsWith(Files.CLASS_FILE_EXTENSION)) {
continue;
}
if (entry.getName().startsWith(packNamePath)) {
if (scanRecursively) {
foundClasses.add(Files.filenameToClassname(entry.getName()));
} else {
String[] parts = splitBySlash(entry.getName());
if (parts.length == expectedPartsLength) {
foundClasses.add(Files.filenameToClassname(entry.getName()));
}
}
}
}
} catch (IOException e) {
CommonLogger.LOG.couldNotReadResource(resourceUri, e);
} finally {
if (jar != null) {
try {
jar.close();
} catch (IOException ignored) {
}
}
}
}
}
private String[] splitBySlash(String value) {
return value.split("/");
}
private boolean isEnabled(String key, boolean defaultValue) {
Object value = properties.get(key);
if (value != null) {
return Boolean.TRUE.equals(value);
}
String system = AccessController.doPrivileged(new GetSystemPropertyAction(key));
if (system != null) {
return Boolean.valueOf(system);
}
return defaultValue;
}
private static class PackInfo {
private final String packName;
private final String packClassName;
private final boolean scanRecursively;
private final WeakReference classLoaderRef;
PackInfo(Class> packClass, boolean recursiveScan) {
this.packName = packClass.getPackage().getName();
this.packClassName = packClass.getName();
this.scanRecursively = recursiveScan;
this.classLoaderRef = new WeakReference(AccessController.doPrivileged(new GetClassLoaderAction(packClass)));
}
PackInfo(Package pack, boolean recursiveScan) {
this.packName = pack.getName();
this.scanRecursively = recursiveScan;
this.packClassName = null;
this.classLoaderRef = null;
}
public String getPackName() {
return packName;
}
public String getPackClassName() {
return packClassName;
}
public boolean isScanRecursively() {
return scanRecursively;
}
public URL getResourceUrl(ResourceLoader resourceLoader) {
if (classLoaderRef != null) {
return classLoaderRef.get().getResource(this.getPackClassName().replace('.', '/') + Files.CLASS_FILE_EXTENSION);
} else {
return resourceLoader.getResource(getPackName().replace('.', '/'));
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((packClassName == null) ? 0 : packClassName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PackInfo other = (PackInfo) obj;
if (packClassName == null) {
if (other.packClassName != null) {
return false;
}
} else if (!packClassName.equals(other.packClassName)) {
return false;
}
return true;
}
}
}