Apache Aries CDI

Clone this repo:
  1. d7cdceb Merge pull request #26 from rotty3000/ARIES-1958 by Raymond Augé · 10 hours ago master
  2. d2fde62 ARIES-1958 stabilize by Raymond Augé · 11 hours ago
  3. f33b1e7 stabilize with better handling of CDI.current() by Raymond Augé · 17 hours ago
  4. 34a25c3 Merge pull request #25 from rotty3000/ARIES-1958 by Raymond Augé · 12 hours ago
  5. 215dcd3 ARIES-1958 let implicit extensions work even if no explicit extensions are required by Raymond Augé · 3 days ago

Aries CDI Integration

Build Status Maven Central

This is an implementation of OSGi CDI Integration Specification (hereafter referred to simply as OSGi CDI).

License

Apache License Version 2.0

Building From Source

The build uses maven so it should look pretty familiar to most developers.

mvn clean install

Depedencies

The main artifact is the CDI Component Runtime (CCR) implementation. a.k.a. the extender bundle:

<dependency>
  <groupId>org.apache.aries.cdi</groupId>
  <artifactId>org.apache.aries.cdi.extender</artifactId>
  <version>${aries-cdi.version}</version>
  <scope>runtime</scope>
</dependency>

However all the required dependencies are available using the Aries CDI BOM:

<dependency>
    <groupId>org.apache.aries.cdi</groupId>
    <artifactId>org.apache.aries.cdi.bom</artifactId>
    <version>${aries-cdi.version}</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

Tooling

In order to make the best use of OSGi CDI you should use tooling that supports it. Bnd provides OOTB support for OSGi CDI annotations and enables a painless configuration model.

OSGi CDI support in bnd comes with any tool that uses bnd versions 4.1.0+:

Note there are several improvements for CDI handling in later versions of bnd, so please use the latest version for best experience.

Setting up

Bean discovery in bnd is handled by the -cdiannotations instruction. The default value for this is * (which is functionally equivalent to *;discover=annotated_by_bean described below.)

Discovery is controlled by applying the attribute discover to glob pattern used for matching classes in the bundle by their fully qualified names (the default glob * matches all classes.)

Available discover options are:

  • none - disable bean discovery
  • annotated - uses the CDI definition of annotated discovery mode
  • all - discover all classes which could be beans
  • annotated_by_bean - defined by bnd, this is the effective default which means to look for classes annotated with org.osgi.service.cdi.annotations.Bean or packages annotated with org.osgi.service.cdi.annotations.Beans)

In combination the glob and modes give the developer very concise control over discovery.

If you want to emulate the CDI default use:

-cdiannotations: *;discover=annotated

beans.xml

In bnd 4.3.0+ you can rely purely on the discovery mode calculated from existing beans.xml files in your project. This grants even less configuration friction for existing projects migrating to OSGi CDI.

Pre-built runtimes

This repository provides two examples for how to assemble an executable jar providing a complete runtime for you to just drop in your CDI bundles. These come complete with logging, Gogo shell, Config Admin, Http Whiteboard support, and OSGi Promises.

Once you've completed a successful build, you should be able to execute the commands:

OpenWebBeans

java -jar cdi-executable/target/weld-executable.jar

and be presented a gogo shell prompt running in a framework that uses Aries CDI over Apache OpenWebBeans ready for you to install a CDI bundle.

Weld

java -jar cdi-executable/target/owb-executable.jar

and be presented with a gogo shell prompt running in a framework that uses Aries CDI over JBoss Weld ready for you to install a CDI bundle.

Architecture Overview

The goal of OSGi CDI was to remain as true to both technologies as possible. This proved possible due to the extensive feature set provided by each technology.

I just have a few questions!

FAQ

Actors

The main actors in the OSGi CDI architecture are:

  • CDI bundle - bundles which contain CDI beans and opted-in to OSGi CDI (best achieved with supporting build tooling.)

  • CDI container - an instance of the CDI machinery hosting all beans inside a bundle and managing their instantiation.

  • CDI Component Runtime (CCR) - is what Aries CDI implements using the extender pattern. It awaits CDI bundles creating a private CDI container for each one.

  • OSGi CDI Components (hereafter referred to simple as components) - A set of closely related CDI beans having a common OSGi lifecycle. A CDI bundle has 1 to N components. Again, all beans within the same component have a common OSGi lifecycle within the CDI bundle. The collective dependencies declared by all bean making up a component are treated as a single set. As such any single unsatisfied dependency of the component will prevent the entire component from activating, or upon removal, will cause the component to deactivate.

  • OSGi CDI Portable Extension (hereafter referred to simply as portable extensions) - bundles which contain portable extensions and opted-in to providing those extensions in a OSGi CDI compatible way.

  • Service Registry - The OSGi service registry is the central actor by which all inter bundle service activity is managed. As such, CDI bundles interact with other bundles via the service registry as well.

    The nice thing is you can mix and match through the lingua franca of services. A bundle that is internally implemented with DS can talk to a bundle that is internally implemented with CDI (or Blueprint, etc...) Neil Bartlett - Twitter

  • Configuration Admin - OSGi CDI is well integrated with Configuration Admin the way that Declarative Services (DS) is. As such, all components in CDI bundles are configurable via configuration admin.

How a CDI bundle is created

When a CDI bundle is identified by CCR several steps are taken before any bean is instantiated:

  1. Any portable extensions identified by the bundle must be discovered and their associated javax.enterprise.inject.spi.Extension services must be located. The bundle's CDI container will remain inactive until all portable extension services are located. Conversely, for a bundle with an active CDI container, if an identified extension goes away the CDI container is torn down.
  2. The beans of the bundle are analysed and categorised into 3 classifications:
    1. Container component:
      • All beans you would traditionally find in a CDI application; ApplicationScoped, Dependent, RequestScoped, SessionScoped, ConversationScoped, any custom scopes, etc.; all of these make up the container component.
      • In fact, all beans that are not specifically org.osgi.service.cdi.annotations.ComponentScoped are part of the container component.
      • Every CDI bundle has exactly 1 container component.
      • It is perfectly valid for the set of container component beans to be empty.
    2. Single component:
      • All beans using the stereotype @SingleComponent are roots of a single component.
      • Any referred beans (via injection points) that are explicitly scoped @ComponentScoped are also part of this single component.
      • Each single component in a bundle has an independent OSGi lifecycle, with one restriction; the container component must be active.
      • if the container component becomes unresolved, active single components are deactivated.
      • A bundle may have 0 to N single components.
      • Single components are directly analogous to DS components that are not flipped to factory mode.
    3. Factory component:
      • All beans using the stereotype @FactoryComponent are roots of a factory component.
      • Any referred beans (via injection points) that are explicitly scoped @ComponentScoped are also part of this factory component.
      • Each factory component in a bundle has an independent OSGi lifecycle, with one restriction; the container component must be active.
      • if the container component becomes unresolved, active factory components are deactivated.
      • A bundle may have 0 to N factory components.
      • Factory components are directly analogous to DS components that are flipped to factory mode.
      • Factory components are dependent on factory configuration instances.
  3. The bundle's CDI container remains inactive while there remain unsatisfied dependencies of the container component. These may be services or configurations.
  4. Once the container component is resolved:
    1. CDI container is created and activated.
    2. the application scope is activated (if there are any such beans in the container component.)
    3. services provided by the container component are published to the service registry (if any.)
    4. The javax.enterprise.inject.spi.BeanManager of the CDI container is published as a service with the service property osgi.cdi.container.id. (always, even if the container component is empty.)
    5. single components and factory components remain inactive while there remain unsatisfied dependencies. These may be services or configurations.
    6. Once a single component is resolved:
      1. it becomes active; the exact nature of which is determined by whether the component provides a service or not, and what the service scope is.
        • if the component does not provide a service, the component is simply instantiated.
        • if the component provides a singleton scoped service, the component is instantiated and published into the registry (wrapped in a ServiceFactory like DS component services)
        • if the component provides a bundle scoped service, the component is published into the registry (wrapped in a ServiceFactory). Service instances are created whenever the getService method of the factory is called, and destroyed when the ungetService is called. Note: The service registry is the one tracking if a bundle has already gotten factory service instances.
        • if the component provides a prototype scoped service, the component is published into the registry (wrapped in a PrototypeServiceFactory). Service instances are created whenever the getService method of the factory is called, and destroyed when the ungetService is called.
      2. if any required dependency of the component goes away, any service registration is removed from the registry and all instances are destroy.
      3. Note that CDI context events whose payload is the component instance are fired at the appropriate moment for each of:
        • @Initialized(ComponentScoped.class)
        • @BeforeDestroy(ComponentScoped.class)
        • @Destroyed(ComponentScoped.class)
    7. Once a factory component is resolved (when a factory configuration instance is created in addition to all other service & configuration dependencies):
      1. an instance becomes active; the exact nature of which is determined by whether the component provides a service or not, and what the service scope is.
        • if the component does not provide a service, the component is simply instantiated.
        • if the component provides a singleton scoped service, the component is instantiated and published into the registry (wrapped in a ServiceFactory like DS component services)
        • if the component provides a bundle scoped service, the component is published into the registry (wrapped in a ServiceFactory). Service instances are created whenever the getService method of the factory is called, and destroyed when the ungetService is called. Note: The service registry is the one tracking if a bundle has already gotten factory service instances.
        • if the component provides a prototype scoped service, the component is published into the registry (wrapped in a PrototypeServiceFactory). Service instances are created whenever the getService method of the factory is called, and destroyed when the ungetService is called.
      2. if any required dependency of the component goes away, any service registration is removed from the registry and all instances are destroy.
      3. Note that CDI context events whose payload is the component instance are fired at the appropriate moment for each of:
        • @Initialized(ComponentScoped.class)
        • @BeforeDestroy(ComponentScoped.class)
        • @Destroyed(ComponentScoped.class)

Aries CDI SPI

Aries CDI now has an SPI for enabling it to be used with any CDI container impl.

The requirements to satisfy this SPI are quite simple:

  • Aries CDI Extender requires:

    • a prototype scoped service that implements org.apache.aries.cdi.spi.CDIContainerInitializer

    • The behaviour of this container should be to start the @ApplicationScoped context immediately. This allows for services from the container component to be published right away.

Check out the many questions and answers in the FAQ.