All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.weld.environment.se.Weld Maven / Gradle / Ivy

There is a newer version: 3.0.0.Alpha1
Show newest version
/*
 * 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... extensionClasses) { for (Class 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... alternativeStereotypeClasses) { selectedAlternativeStereotypes.clear(); for (Class 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 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... alternativeStereotypeClasses) { for (Class 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 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; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy