Weld SiteCommunity Documentation

Appendix A. Integrating Weld into other environments

If you want to use Weld in another environment, you will need to provide certain information to Weld via the integration SPI. In this Appendix we will briefly discuss the steps needed.

If you are upgrading existing Weld integration to work with Weld 2, see this migration document.

Note

If you just want to use managed beans, and not take advantage of enterprise services (EE resource injection, CDI injection into EE component classes, transactional events, support for CDI services in EJBs) and non-flat deployments, then the generic servlet support provided by the "Weld: Servlets" extension will be sufficient, and will work in any container supporting the Servlet API.

All SPIs and APIs described have extensive JavaDoc, which spell out the detailed contract between the container and Weld.

The Weld SPI is located in the weld-spi module, and packaged as weld-spi.jar. Some SPIs are optional, and should only be implemented if you need to override the default behavior; others are required.

All interfaces in the SPI support the decorator pattern and provide a Forwarding class located in the helpers sub package. Additional, commonly used, utility classes, and standard implementations are also located in the helpers sub package.

Weld supports multiple environments. An environment is defined by an implementation of the Environment interface. A number of standard environments are built in, and described by the Environments enumeration. Different environments require different services to be present (for example a Servlet container doesn’t require transaction, EJB or JPA services). By default an EE environment is assumed, but you can adjust the environment by calling bootstrap.setEnvironment().

Weld uses services to communicate with its environment. A service is a java class that implements the org.jboss.weld.bootstrap.api.Service interface and is explicitly registered. A service may be BDA-specific or may be shared across the entire application.

public interface Service {

   public void cleanup();
}

Certain services are only used at bootstrap and need to be cleaned up afterwards in order not to consume memory. A service that implements the specialized org.jboss.weld.bootstrap.api.BootstrapService interface receives a cleanupAfterBoot() method invocation once Weld initialization is finished but before the deployment is put into service.

public interface BootstrapService extends Service {

    void cleanupAfterBoot();
}

Weld uses a generic-typed service registry to allow services to be registered. All services implement the Service interface. The service registry allows services to be added and retrieved.

An application is often comprised of a number of modules. For example, a Java EE deployment may contain a number of EJB modules (containing business logic) and war modules (containing the user interface). A container may enforce certain accessibility rules which limit the visibility of classes between modules. CDI allows these same rules to apply to bean and observer method resolution. As the accessibility rules vary between containers, Weld requires the container to describe the deployment structure, via the Deployment SPI.

The CDI specification discusses Bean Archives (BAs)—archives which are marked as containing beans which should be deployed to the CDI container, and made available for injection and resolution. Weld reuses this description and uses Bean Deployment Archives (BDA) in its deployment structure SPI.

Each deployment exposes the containing BDAs that form a graph. A node in the graph represents a BDA. Directed edges between nodes designate visibility. Visibility is not transitive (i.e. a bean from BDA A can only see beans in BDAs with which A is directly connected by a properly oriented edge).

To describe the deployment structure to Weld, the container should provide an implementation of Deployment. Deployment.getBeanDeploymentArchives() allows Weld to discover the modules which make up the application. The CDI specification also allows beans to be specified programmatically as part of the bean deployment. These beans may, or may not, be in an existing BDA. For this reason, Weld will call Deployment.loadBeanDeploymentArchive(Class clazz) for each programmatically described bean.

As programmatically described beans may result in additional BDAs being added to the graph, Weld will discover the BDA structure every time an unknown BDA is returned by Deployment.loadBeanDeploymentArchive.

BeanDeploymentArchive provides three methods which allow it’s contents to be discovered by Weld—BeanDeploymentArchive.getBeanClasses() must return all the classes in the BDA, BeanDeploymentArchive.getBeansXml() must return a data structure representing the beans.xml deployment descriptor for the archive, and BeanDeploymentArchive.getEjbs() must provide an EJB descriptor for every EJB in the BDA, or an empty list if it is not an EJB archive.

To aid container integrator, Weld provides a built-in beans.xml parser. To parse a beans.xml into the data-structure required by BeanDeploymentArchive, the container should call Bootstrap.parse(URL). Weld can also parse multiple beans.xml files, merging them to become a single data-structure. This can be achieved by calling Bootstrap.parse(Iterable<URL>).

When multiple beans.xml files are merged, Weld keeps duplicate enabled entries (interceptors, decorators or alternatives). This may cause validation problems when multiple physical archives which define an overlapping enabled entries are merged. A version of the Bootstrap.parse() method that provides control over whether duplicate enabled entries are remove or not is provided: Bootstrap.parse(Iterable<URL> urls, boolean removeDuplicates).

BDA X may also reference another BDA Y whose beans can be resolved by, and injected into, any bean in BDA X. These are the accessible BDAs, and every BDA that is directly accessible by BDA X should be returned. A BDA will also have BDAs which are accessible transitively, and the transitive closure of the sub-graph of BDA X describes all the beans resolvable by BDA X.

To specify the directly accessible BDAs, the container should provide an implementation of BeanDeploymentArchive.getBeanDeploymentArchives().

Certain services are provided for the whole deployment, whilst some are provided per-BDA. BDA services are provided using BeanDeploymentArchive.getServices() and only apply to the BDA on which they are provided.

The contract for Deployment requires the container to specify the portable extensions (see chapter 12 of the CDI specification) which should be loaded by the application. To aid the container integrator, Weld provides the method Bootstrap.loadExtensions(ClassLoader) which will load the extensions for the specified classloader.

All the EE resource services are per-BDA services, and may be provided using one of two methods. Which method to use is at the discretion of the integrator.

The integrator may choose to provide all EE resource injection services themselves, using another library or framework. In this case the integrator should use the EE environment, and implement the Section A.1.9, “Injection Services” SPI.

Alternatively, the integrator may choose to use CDI to provide EE resource injection. In this case, the EE_INJECT environment should be used, and the integrator should implement the Section A.1.4, “EJB services”, Section A.1.7, “Resource Services” and Section A.1.5, “JPA services”.

Important

CDI only provides annotation-based EE resource injection; if you wish to provide deployment descriptor (e.g. ejb-jar.xml) injection, you must use Section A.1.9, “Injection Services”.

If the container performs EE resource injection, the injected resources must be serializable. If EE resource injection is provided by Weld, the resolved resource must be serializable.

Tip

If you use a non-EE environment then you may implement any of the EE service SPIs, and Weld will provide the associated functionality. There is no need to implement those services you don’t need!

Weld registers resource injection points with EjbInjectionServices, JpaInjectionServices, ResourceInjectionServices and JaxwsInjectionServices implementations upfront (at bootstrap). This allows validation of resource injection points to be performed at boot time rather than runtime. For each resource injection point Weld obtains a ResourceReferenceFactory which it then uses at runtime for creating resource references.

public interface ResourceReferenceFactory<T> {

    ResourceReference<T> createResource();
}

A ResourceReference provides access to the resource reference to be injected. Furthermore, ResourceReference allows resource to be release once the bean that received resource injection is destroyed.

public interface ResourceReference<T> {

    T getInstance();
    void release();
}

Just as EJB resolution is delegated to the container, resolution of @PersistenceContext for injection into managed beans (with the InjectionPoint provided), is delegated to the container.

To allow JPA integration, the JpaServices interface should be implemented. This service is not required if the implementation of Section A.1.9, “Injection Services” takes care of @PersistenceContext injection.

Note

The following methods were deprecated in Weld 2:

* JpaInjectionServices.resolvePersistenceContext(InjectionPoint injectionPoint) * JpaInjectionServices.resolvePersistenceUnit(InjectionPoint injectionPoint)

An injection point should instead be registered properly using the following methods:

* JpaInjectionServices.registerPersistenceContextInjectionPoint(InjectionPoint injectionPoint) * JpaInjectionServices.registerPersistenceUnitInjectionPoint(InjectionPoint injectionPoint)

The resolution of @Resource (for injection into managed beans) is delegated to the container. You must provide an implementation of ResourceInjectionServices which provides these operations. This service is not required if the implementation of Section A.1.9, “Injection Services” takes care of @Resource injection.

Note

The following methods were deprecated in Weld 2:

* ResourceInjectionServices.resolveResource(InjectionPoint injectionPoint) * ResourceInjectionServices.resolveResource(String jndiName, String mappedName)

An injection point should instead be registered properly using the following methods:

* ResourceInjectionServices.registerResourceInjectionPoint(InjectionPoint injectionPoint) * ResourceInjectionServices.registerResourceInjectionPoint(String jndiName, String mappedName)

The org.jboss.weld.bootstrap.api.Bootstrap interface defines the initialization for Weld, bean deployment and bean validation. To boot Weld, you must create an instance of org.jboss.weld.bootstrap.WeldBeansBootstrap (which implements Bootstrap), tell it about the services in use, and then request the container start.

public interface Bootstrap {

    public Bootstrap startContainer(Environment environment, Deployment deployment);
    public Bootstrap startInitialization();
    public Bootstrap deployBeans();
    public Bootstrap validateBeans();
    public Bootstrap endInitialization();
    public void shutdown();
    public WeldManager getManager(BeanDeploymentArchive beanDeploymentArchive);
    public BeansXml parse(URL url);
    public BeansXml parse(Iterable<URL> urls);
    public BeansXml parse(Iterable<URL> urls, boolean removeDuplicates);
    public Iterable<Metadata<Extension>> loadExtensions(ClassLoader classLoader);
}

The bootstrap is split into phases, container initialization, bean deployment, bean validation and shutdown. Initialization will create a manager, and add the built-in contexts, and examine the deployment structure. Bean deployment will deploy any beans (defined using annotations, programmatically, or built in). Bean validation will validate all beans.

To initialize the container, you call Bootstrap.startInitialization(). Before calling startInitialization(), you must register any services required by the environment. You can do this by calling, for example, bootstrap.getManager().getServices().add(JpaServices.class, new MyJpaServices()). You must also provide the application context bean store.

Having called startInitialization(), the Manager for each BDA can be obtained by calling Bootstrap.getManager(BeanDeploymentArchive bda).

To deploy the discovered beans, call Bootstrap.deployBeans().

To validate the deployed beans, call Bootstrap.validateBeans().

To place the container into a state where it can service requests, call Bootstrap.endInitialization()

To shutdown the container you call Bootstrap.shutdown(). This allows the container to perform any cleanup operations needed.

Integrators with bytecode-scanning capabilities may implement an optional ClassFileServices service.

Bytecode-scanning is used by some application servers to speed up deployment. Compared to loading a class using ClassLoader, bytecode-scanning allows to obtain only a subset of the Java class file metadata (e.g. annotations, class hierarchy, etc.) which is usually loaded much faster. This allows the container to scan all classes initially by a bytecode scanner and then use this limited information to decide which classes need to be fully loaded using ClassLoader. Jandex is an example of a bytecode-scanning utility.

ClassFileServices may be used by an integrator to provide container’s bytecode-scanning capabilities to Weld. If present, Weld will try to use the service to avoid loading of classes that do not need to be loaded. These are classes that:

This usually yields improved bootstrap performance especially in large deployments with a lot of classes in explicit bean archives.

public interface ClassFileServices extends BootstrapService {

    ClassFileInfo getClassFileInfo(String className);
}
public interface ClassFileInfo {

    String getClassName();
    String getSuperclassName();
    boolean isAnnotationDeclared(Class<? extends Annotation> annotationType);
    boolean containsAnnotation(Class<? extends Annotation> annotationType);
    int getModifiers();
    boolean hasCdiConstructor();
    boolean isAssignableFrom(Class<?> javaClass);
    boolean isAssignableTo(Class<?> javaClass);
    boolean isVetoed();
    boolean isTopLevelClass();

See the JavaDoc for more details.

The standard way for an integrator to provide Service implementations is via the deployment structure. Alternatively, services may be registered using the ServiceLoader mechanism. This is useful e.g. for a library running in weld-servlet environment. Such library may provide TransactionServices implementation which would not otherwise be provided by weld-servlet.

A service implementation should be listed in a file named META-INF/services/org.jboss.weld.bootstrap.api.Service

A service implementation can override another service implementation. The priority of a service implementation is determined from the javax.annotation.Priority annotation. Service implementations with higher priority have precedence. A service implementation that does not define priority explicitly is given implicit priority of 4500.

There are a number of requirements that Weld places on the container for correct functioning that fall outside implementation of APIs.

If you are integrating Weld into a JSF environment you must register org.jboss.weld.el.WeldELContextListener as an EL Context listener.

If you are integrating Weld into a JSF environment you must register org.jboss.weld.jsf.ConversationAwareViewHandler as a delegating view handler.

If you are integrating Weld into a JSF environment you must obtain the bean manager for the module and then call BeanManager.wrapExpressionFactory(), passing Application.getExpressionFactory() as the argument. The wrapped expression factory must be used in all EL expression evaluations performed by JSF in this web application.

If you are integrating Weld into a JSF environment you must obtain the bean manager for the module and then call BeanManager.getELResolver(), The returned EL resolver should be registered with JSF for this web application.

If you are integrating Weld into a JSF environment you must register org.jboss.weld.servlet.ConversationPropagationFilter as a Servlet listener, either automatically, or through user configuration, for each CDI application which uses JSF. This filter can be registered for all Servlet deployment safely.

The CDI specification requires the container to provide injection into non-contextual resources for all Java EE component classes. Weld delegates this responsibility to the container. This can be achieved using the CDI defined InjectionTarget SPI. Furthermore, you must perform this operation on the correct bean manager for the bean deployment archive containing the EE component class.

The CDI specification also requires that a ProcessInjectionTarget event is fired for every Java EE component class. Furthermore, if an observer calls ProcessInjectionTarget.setInjectionTarget() the container must use the specified injection target to perform injection.

To help the integrator, Weld provides WeldManager.fireProcessInjectionTarget() which returns the InjectionTarget to use.

// Fire ProcessInjectionTarget, returning the InjectionTarget

// to use
InjectionTarget it = weldBeanManager.fireProcessInjectionTarget(clazz);
// Per instance required, create the creational context
CreationalContext<?> cc = beanManager.createCreationalContext(null);
// Produce the instance, performing any constructor injection required
Object instance = it.produce();
// Perform injection and call initializers
it.inject(instance, cc);
// Call the post-construct callback
it.postConstruct(instance);
// Call the pre-destroy callback
it.preDestroy(instance);
// Clean up the instance
it.dispose(instance);
cc.release();

The container may intersperse other operations between these calls. Further, the integrator may choose to implement any of these calls in another manner, assuming the contract is fulfilled.

When performing injections on EJBs you must use the Weld-defined SPI, WeldManager. Furthermore, you must perform this operation on the correct bean manager for the bean deployment archive containing the EJB.

// Obtain the EjbDescriptor for the EJB

// You may choose to use this utility method to get the descriptor
EjbDescriptor<T> ejbDescriptor = beanManager.<T>getEjbDescriptor(ejbName);
// Get an the Bean object
Bean<T> bean = beanManager.getBean(ejbDescriptor);
// Create the injection target
InjectionTarget<T> it = beanManager.createInjectionTarget(ejbDescriptor);
// Per instance required, create the creational context
WeldCreationalContext<T> cc = beanManager.createCreationalContext(bean);
// register an AroundConstructCallback if needed
cc.setConstructorInterceptionSuppressed(true);
cc.registerAroundConstructCallback(new AroundConstructCallback<T>() {
    public T aroundConstruct(ConstructionHandle<T> handle, AnnotatedConstructor<T> constructor, Object[] parameters,
            Map<String, Object> data) throws Exception {
        // TODO: invoke @AroundConstruct interceptors
        return handle.proceed(parameters, data);
    }
});
// Produce the instance, performing any constructor injection required
T instance = it.produce(cc);
// Perform injection and call initializers
it.inject(instance, cc);
// You may choose to have CDI call the post construct and pre destroy
// lifecycle callbacks
// Call the post-construct callback
it.postConstruct(instance);
// Call the pre-destroy callback
it.preDestroy(instance);
// Clean up the instance
it.dispose(instance);
cc.release();

This part of the appendix documents the changes in Weld across major and minor releases that an integrator should be aware of. These changes mostly touch changes in the SPI or in the container contract.

A new service named HttpContextActivationFilter was added to the Weld SPI. This optional service allows an integrator to decide if CDI contexts should be activated or not for a given HTTP request. By default, CDI contexts are always active but this hook allows an integrator to eliminate the overhead of CDI context activation for certain types of requests where CDI is known not to be needed (e.g. request for a static resource).

Note that when the service is provided, user configuration is overriden.

The BootstrapConfiguration service now allows the non-portable mode to be enabled by the integrator.

Since Weld 2.1 the Singleton SPI requires the singleton to be identified by a String context id. This allows multiple Weld containers to run at the same time in environments where the TCCL cannot be used to distinguish the containers (e.g. OSGi environment).

The integrator should:

  • implement the new methods
  • use WeldBootstrap.startContainer(String contextId, Environment environment, Deployment deployment) to start Weld
  • eliminate all Container.instance() calls and replace them with Container.instance(String contextId)

The Weld-OSGi bundle does no include Weld’s runtime dependencies anymore. Therefore, it is possible to deploy the following artifacts in order to satisfy Weld’s dependencies:

group idartifact idversion

org.jboss.logging

jboss-logging

3.1.3.GA

javax.enterprise

cdi-api

1.1-20130918

javax.annotation

javax.annotation-api

1.2

javax.interceptor

javax.interceptor-api

1.2

org.apache.geronimo.specs

geronimo-el_2.2_spec

1.0.3

group idartifact idversion

org.jboss.classfilewriter

jboss-classfilewriter

1.1.2.Final