SeamFramework.orgCommunity Documentation

CDI OSGi integration

Design Specification


1. Preface
1.1. About naming and references
1.1.1. Bean archive
1.1.2. OSGi bundle
1.1.3. Bean bundle
1.1.4. References
1.2. What are CDI-OSGi and Weld-OSGi ?
1.2.1. CDI-OSGi
1.2.2. Weld-OSGi
1.2.3. Organization and interactions between CDI-OSGi bundles
1.3. What about other frameworks
1.4. Organization of this document
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
3. How to make OSGi easy peasy
3.1. CDI usage in bean bundles
3.2. Injecting easiness in OSGi world
3.2.1. Service, implementation, instance and registration
3.2.2. OSGi services injection
3.2.3. OSGi service automatic publishing with @Publish annotation
3.2.4. Clearly specify a service implementation
3.2.5. Contextual services
3.2.6. The registration
3.2.7. Service registry
3.2.8. The OSGiServiceUnavailableException exception
3.3. CDI-OSGi events
3.3.1. CDI container lifecycle events
3.3.2. Bundle lifecycle events
3.3.3. Service lifecyle events
3.3.4. Application dependency validation events
3.3.5. Intra and inter bundles communication events
3.4. OSGi utilities
3.4.1. From the current bundle
3.4.2. From external bundle
3.5. CDI-OSGi, what else ?
3.5.1. Getting service references and instances
3.5.2. Publishing a service implementation
3.5.3. Obtaining the Bundles and BundleContexts
4. Weld-OSGi implementation

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):

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.

CDI-OSGi provides more functionality using CDI in a OSGi environment.

It mainly focuses on the OSGi service layer. It addresses the difficulties in publishing and consuming services. CDI-OSGi allows developers to publish and consume OSGi services as CDI beans. However, since OSGi services are dynamic there are some differences with classic bean injection. This section presents how OSGi services can be published and consumed using CDI-OSGi.

CDI-OSGi also provides utilities for event notification and communication in and between bundles as well as some general OSGi utilities.

Examples use this very sophisticated service interface:

public interface MyService {
    void doSomething();
}

There are two ways to obtain a service instances using CDI-OSGi: direct injection and programmatic lookup.

There might be multiple implementations of the same service. It is possible to provide properties to an implementation in CDI-OSGi. This qualification is available both during publishing and consuming.

There are two ways for qualifying: a CDI like and a OSGi like, both are presented below.

A registration object represent all the bindings between a service contract class and its OSGi ServiceRegistrations. With this object it is possible to navigate through multiple implementations of the same service, obtain the corresponding Service<T> or unregister these implementations.

CDI-OSGi makes heavy usage of CDI events. These events allow CDI-OSGi to do its work. Events are important for the running of CDI-OSGi itself but they can also be used by client bean bundles to perform some operations or override some normal CDI-OSGi behavior.

This section shows the numerous events provided by CDI-OSGi and the ways to use them.

Ten events might be fired during a bundle lifecycle. They represent the possible states of a bundle and monitor the changes occurred in bundle lifecycles. These events carry the Bundle object from where the event comes so developers can retrieve useful information (such as the bundle id).

Three events might be fired during a service lifecycle. They represent the possible states of a service and monitor the changes occurred in service lifecycles. These events carry the BundleContext object from where the event comes and the ServiceReference object corresponding to the service so developers can retrieve useful information (such as the registering bundle) and acces useful actions (such as register or unregister services).

Here there are some examples that concretely show what CDI-OSGi is avoiding to the developer: