SeamFramework.orgCommunity Documentation

Chapter 2. Organization of CDI-OSGi

2.1. API bundles, extension bundle and integration bundle
2.1.1. Extension API, integration API and CDI API
2.1.2. Extension bundle: the puppet master
2.1.3. Integration bundle: choose a CDI compliant container
2.2. An OSGi extension for CDI support: the extension API
2.2.1. CDI-OSGi features
2.2.2. The interfaces
2.2.3. The events
2.2.4. The annotations
2.3. A standard bootstrap for CDI container integration: the integration API
2.3.1. Why an integration API
2.3.2. Integration bundle discovery and CDI-OSGi start
2.3.3. Embedded mode
2.4. An orchestrator: the extension bundle
2.4.1. The extender pattern
2.4.2. The extension bundle works that way:
2.5. A interchangeable CDI container factory: the integration bundle
2.5.1. A implementation bundle may work that way:
2.6. The life of a bean bundle
2.7. How to make a bundle or a bean archive a bean bundle
2.7.1. The META-INF/bean.xml file
2.7.2. The Embedded-CDIContainer META-INF/Manifest.MF header

CDI-OSGi is composed of five bundles:

Note that as CDI-OSGi runs in an OSGi environment it is implicit that there is an OSGi core bundle too. This one provide OSGi features for all other bundles, including CDI-OSGi managed bundles. But it is not an actual part of CDI-OSGi.

Three API bundles expose all packages that could be needed by developers; both for client applications using CDI-OSGi and for CDI compliant container integration. Their packages may be imported by bean bundles, extension bundle or implementation bundle.

These three distinct API are:

These three API are more described below.

Extension API provides few interfaces that describe all specifics about OSGi service injection.

Extension API provides numerous events that notify about life-cycle steps for CDI container management, service management, bundle management, bean bundle validation and bundle communication management. They all use CDI event system.

CDI container events, as well as service and bundle events, are regrouped using three classes. Thus each category of event has:

The representing abstract class:

public abstract class AbstractBundleEvent {

    private final Bundle bundle;

    public AbstractBundleEvent(Bundle bundle) {...}
    
    public abstract BundleEventType getType();
    public long getBundleId() {...}
    public String getSymbolicName() {...}
    public Version getVersion() {...}
    public Bundle getBundle() {...}
}

This abstract class represents all the CDI-OSGi bundle events as a superclass.

It allows to:

It may be used in Observes method in order to listen all bundle events.

The possible event types:

public enum BundleEventType {

    INSTALLED,
    LAZY_ACTIVATION,
    RESOLVED,
    STARTED,
    STARTING,
    STOPPED,
    STOPPING,
    UNINSTALLED,
    UNRESOLVED,
    UPDATED,
}

This enumeration lists all possible states of a bundle and the corresponding event types.

The implementation classes (in the global event class):

public class BundleEvents {

    public static class BundleInstalled extends AbstractBundleEvent {

        public BundleInstalled(Bundle bundle) {...}

        @Override
        public BundleEventType getType() {...}
    }
    //next classes follow the same template as above
    public static class BundleLazyActivation extends AbstractBundleEvent {...}
    public static class BundleResolved extends AbstractBundleEvent {...}
    public static class BundleStarted extends AbstractBundleEvent {...}
    public static class BundleStarting extends AbstractBundleEvent {...}
    public static class BundleStopped extends AbstractBundleEvent {...}
    public static class BundleStopping extends AbstractBundleEvent {...}
    public static class BundleUninstalled extends AbstractBundleEvent {...}
    public static class BundleUnresolved extends AbstractBundleEvent {...}
    public static class BundleUpdated extends AbstractBundleEvent {...}
}

This class wraps all the bundle events as inner static classes. There is one event class by BundleEventType.

Each inner class allows to:

They may be used in Observes method in order to listen a specific bundle event.

The representing abstract class:

public abstract class AbstractServiceEvent {

    private final ServiceReference reference;
    private final BundleContext context;
    private List<String> classesNames;
    private List<Class<?>> classes;
    private Map<Class, Boolean> assignable;

    public AbstractServiceEvent(ServiceReference reference, BundleContext context) {...}
    
    public abstract ServiceEventType eventType();
    public ServiceReference getReference() {...}
    public <T> TypedService<T> type(Class<T> type) {...}
    public Object getService() {...}
    public boolean ungetService() {...}
    public boolean isTyped(Class<?> type) {...}
    public Bundle getRegisteringBundle() {...}
    public List<String> getServiceClassNames() {...}
    public List<Class<?>> getServiceClasses() {...}

    public static class TypedService<T> {

        private final BundleContext context;
        private final ServiceReference ref;
        private final Class<T> type;

        TypedService(BundleContext context, ServiceReference ref, Class<T> type) {...}
        
        static <T> TypedService<T> create(Class<T> type, BundleContext context, ServiceReference ref) {...}
        public T getService() {...}
        public boolean ungetService() {...}
    }
}

This abstract class represents all the CDI-OSGi service events as a superclass.

It allows to:

It may be used in Observes method in order to listen all service events.

The possible event types:

public enum ServiceEventType {

    SERVICE_ARRIVAL,
    SERVICE_DEPARTURE,
    SERVICE_CHANGED
}

This enumeration lists all possible states of a service and the corresponding event types.

The implementation classes (in the global event class):

public class ServiceEvents {

    public static class ServiceArrival extends AbstractServiceEvent {

        public ServiceArrival(
                ServiceReference ref, BundleContext context) {
            super(ref, context);
        }

        @Override
        public ServiceEventType eventType() {
            return ServiceEventType.SERVICE_ARRIVAL;
        }
    }
    //next classes follow the same template as above
    public static class ServiceChanged extends AbstractServiceEvent {...}
    public static class ServiceDeparture extends AbstractServiceEvent {...}

}

This class wraps all the service events as inner static classes. There is one event class by ServiceEventType.

Each inner class allows to:

They may be used in Observes method in order to listen a specific service event.

The representing abstract class:

public abstract class AbstractBundleContainerEvent {

    private BundleContext bundleContext;

    public AbstractBundleContainerEvent(final BundleContext context) {...}

    public abstract BundleContainerEventType getType();
    public BundleContext getBundleContext() {...}
}

This abstract class represents all the CDI-OSGi bundle container events as a superclass.

It allows to:

It may be used in Observes method in order to listen all bundle container events.

The possible event types:

public enum BundleContainerEventType {

    INITIALIZED,
    SHUTDOWN
}

This enumeration list all possible states of a bundle container and the corresponding event types.

The implementation classes (in the global event class):

public class BundleContainerEvents {

    public static class BundleContainerInitialized extends AbstractBundleContainerEvent {

        public BundleContainerInitialized(BundleContext context) {
            super(context);
        }

        @Override
        public BundleContainerEventType getType() {
            return BundleContainerEventType.INITIALIZED;
        }
    }
    //next class follows the same template as above
    public static class BundleContainerShutdown extends AbstractBundleContainerEvent {...}
}

This class wraps all the bundle container events as inner static classes. There is one event class by BundleContainerEventType.

Each inner class allows to:

They may be used in Observes method in order to listen a specific bundle container event.

Two events notify about the validation of bean bundle. After it starts a bean bundle should validate its required service dependencies. The Valid and Invalid events occurs when such dependencies are fulfilled or unfulfilled. These two new states are described in an enumeration: BundleState.

public class Valid {

    private final Bundle bundle;

    public Valid(Bundle bundle) {...}

    public long getBundleId() {...}
    public String getSymbolicName() {...}
    public Version getVersion() {...}
    public Bundle getBundle() {...}
}

This class represents all bean bundle validation event.

It allows to:

It may be used in Observes method in order to listen all bean bundle validation events.

public class Invalid {

    private final Bundle bundle;

    public Invalid(Bundle bundle) {...}

    public long getBundleId() {...}
    public String getSymbolicName() {...}
    public Version getVersion() {...}
    public Bundle getBundle() {...}
}

This class represents all bean bundle invalidation event.

It allows to:

It may be used in Observes method in order to listen all bean bundle invalidation events.

public enum BundleState {
    VALID, INVALID
}

This enumeration lists the two new states of a bean bundle.

A bean bundle is in VALID state if all its required service dependencies are validated otherwise is in INVALID state. Every time a bean bundle goes from one state to another a corresponding Valid or Invalid event may be fired.

Extension API provides annotations in order to easily use CDI-OSGi features.

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface OSGiBundle {
    @Nonbinding String value();
    @Nonbinding String version() default "";
}

This annotation qualifies an injection point that represents a bundle or a bundle relative object.

It allows to specify:

The symbolic name and version are not actually qualifying the injection point, thus this annotation is for global bundle injection point with additional data. In order to actually discriminate on the symbolic name or version see BundleName and BundleVersion annotations.

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BundleName {
    String value();
}

This annotation qualifies an injection point that represents a bundle or a bundle relative object.

It allows to specify the symbolic name of the bundle, as a required value.

The symbolic name actually discriminate the injection point, thus this annotation is for specific bundle relative injection point. For global bundle relative injection point see OSGiBundle annotation. To discriminate the bundle version see BundleVersion.

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BundleVersion {
    String value();
}

This annotation qualifies an injection point that represents a bundle or a bundle relative object.

It allows to specify the version of the bundle, as a required value.

The version actually discriminate the injection point, thus this annotation is for specific bundle relative injection point. For global bundle relative injection point see OSGiBundle annotation. To discriminate the bundle symbolic name see BundleName.

CDI-OSGi could have been carried out with an internal CDI compliant container and work very well. Every one of the specifications above would have been fulfilled. But no other specific utilities or CDI evolution could have been added without a complete modification of CDI-OSGi.

Then there is the integration API. With that, developers are able to provide their own integration bundle. Thus it is possible to use any CDI compliant container with a CDI-OSGi application or mix up different CDI compliant containers for different bundles.

Integration API describes what needs the extension bundle to work (and therefore what may provide the integration bundle):

The integration bundle is necessary in a CDI-OSGi application. This section explains the part the integration bundle plays but does not enter in specifics because it depends on the CDI implementation used.

Weld-OSGi chapter presents how an implementation bundle can work.

This section presents the lifecycle of a bean bundle and how it impacts CDI and OSGi regular behaviors. Mostly bean bundles follow the same lifecycle than a regular bundle. There are only two new possible states and they do not modify the behavior from OSGi side.


The regular OSGi lifecycle is not modified by the new CDI-OSGi states as they have the same meaning than the ACTIVE state from an OSGi point of view. They only add information about the validation of required service availability.

There are very few things to do in order to obtain a bean bundle from a bean archive or a bundle. Mostly it is just adding the missing marker files and headers in the archive:

Thus a bean bundle has both META-INF/bean.xml file and OSGi marker headers in its META-INF/Manifest.MF file.

However there is a few other information that CDI-OSGi might need in order to perform a correct extension. In particular a bean bundle can not be manage by the extension bundle but by his own embedded CDI container. For that there is a new manifest header.