SeamFramework.orgCommunity Documentation

Weld - OSGi integration

The power of modularity for CDI


1. Weld-OSGi user documentation
1.1. What is this documentation
1.2. What is Weld-OSGi
1.3. Naming convention
1.4. What tools are used in this documentation
1.5. References and other documentations
2. Getting started with Weld-OSGi
2.1. Setting up your environment
2.2. Say hello to the World: your first bean bundle
2.3. CDI usage in bean bundle: a more complex example
3. Weld-OSGi addressing OSGi service layer complexity
3.1. Publishing CDI beans as OSGi services
3.2. Consuming Weld-OSGi auto published services
3.3. Select the service instance
3.4. Injecting OSGi service in bean bundle
4. Weld-OSGi addressing event notification and comunication
4.1. Get OSGi event notifications in your bean bundles
4.2. Use your own inter bundle notifications
5. OSGi is still alive

In this chapter you will see:

  • how to setup the environment in order to use Weld-OSGi

  • how to build your first bean bundle using CDI in OSGi

  • how to build a more complex example with advanced CDI usage

Weld-OSGi may run in an OSGi environment, you should setup one:

Try your Felix installation a bit with these three main command:

  • The lb command, that lists all the bundles in the OSGi environment, with their id and state (currently you only have the Felix framework utility bundles)

    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (3.2.2)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
        2|Active     |    1|Apache Felix Gogo Command (0.8.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.8.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.8.0)
    g! 
  • The stop <bundle_id> command, that stops the corresponding bundle

    g! stop 1
    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (3.2.2)
        1|Resolved   |    1|Apache Felix Bundle Repository (1.6.2)
        2|Active     |    1|Apache Felix Gogo Command (0.8.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.8.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.8.0)
    g! 
  • The start <bundle_id> command, that starts the corresponding bundle

    g! start 1
    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (3.2.2)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
        2|Active     |    1|Apache Felix Gogo Command (0.8.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.8.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.8.0)
    g! 

Felix framework currently auto start all bundles, although it is a good thing for utility bundles it may be inconvenient with application bundles. You should configure the Felix framework by editing the Felix home conf/config.properties file:

  • Unable the auto start option by replacing the line

    felix.auto.deploy.action=install,start

    by

    #felix.auto.deploy.action=install,start
  • Ask for auto start of utility bundle by replacing the line

    #felix.auto.start.1=

    by

    felix.auto.start.1= file:bundle/org.apache.felix.bundlerepository-1.6.2.jar \
    file:bundle/org.apache.felix.gogo.command-0.8.0.jar \
    file:bundle/org.apache.felix.gogo.runtime-0.8.0.jar \
    file:bundle/org.apache.felix.gogo.shell-0.8.0.jar

Install Weld-OSGi in the Felix framework:

  • Add some bundle in the Felix framework by simply drop the corresponding jar files into the bundle directory of Felix home

  • Download the last version of Weld-OSGi here: TBA

  • Extract the five bundles into the bundle directory of Felix home

    Get Felix up to date

    Felix framework keeps a cache of old bundles and actions you performed. You may remove the Felix home felix-cache directory to avoid older versions of bundle and configuration to be taken into account when:

    • You add/remove bundles from bundle directory

    • You modify the conf/config.properties file

    • You restart the Felix framework after running some commands

  • Update the Felix framework configuration file in order to auto install the Weld-OSGi bundle by replacing the line

    #felix.auto.install.1=

    by

    felix.auto.install.1= file:bundle/weld-osgi-core-api-1.0-SNAPSHOT.jar \
    file:bundle/weld-osgi-core-extension-1.0-SNAPSHOT.jar \
    file:bundle/weld-osgi-core-spi-1.0-SNAPSHOT.jar \
    file:bundle/weld-osgi-core-mandatory-1.0-SNAPSHOT.jar \
    file:bundle/weld-osgi-core-integration-1.0-SNAPSHOT.jar
  • Check the bundle are in the OSGi environment by starting the Felix framework

    ____________________________
    Welcome to Apache Felix Gogo
    
    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (3.2.2)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
        2|Active     |    1|Apache Felix Gogo Command (0.8.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.8.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.8.0)
        5|Installed  |    1|Weld-OSGi :: Core :: Extension API (1.0.0.SNAPSHOT)
        6|Installed  |    1|Weld-OSGi :: Core :: Extension Impl (1.0.0.SNAPSHOT)
        7|Installed  |    1|Weld-OSGi :: Core :: Integration API (1.0.0.SNAPSHOT)
        8|Installed  |    1|Weld-OSGi :: Core :: Mandatory (1.0.0.SNAPSHOT)
        9|Installed  |    1|Weld-OSGi :: Implementation :: Weld Integration (1.0.0.SNAPSHOT)
    g! 
  • Run the bundles Weld-OSGi :: Core :: Extension Impl and Weld-OSGi :: Implementation :: Weld Integration in order to get the Weld-OSGi running in the Felix framework

    g! start 6
    g! start 9
    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (3.2.2)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
        2|Active     |    1|Apache Felix Gogo Command (0.8.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.8.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.8.0)
        5|Resolved   |    1|Weld-OSGi :: Core :: Extension API (1.0.0.SNAPSHOT)
        6|Active     |    1|Weld-OSGi :: Core :: Extension Impl (1.0.0.SNAPSHOT)
        7|Resolved   |    1|Weld-OSGi :: Core :: Integration API (1.0.0.SNAPSHOT)
        8|Resolved   |    1|Weld-OSGi :: Core :: Mandatory (1.0.0.SNAPSHOT)
        9|Active     |    1|Weld-OSGi :: Implementation :: Weld Integration (1.0.0.SNAPSHOT)
    g! 

It would be easier if these two bundles were auto started with Felix framework.

  • Modify the Felix configuration file to do so

    felix.auto.install.1= file:bundle/weld-osgi-core-api-1.0-SNAPSHOT.jar \
    file:bundle/weld-osgi-core-spi-1.0-SNAPSHOT.jar \
    file:bundle/weld-osgi-core-mandatory-1.0-SNAPSHOT.jar
    ...
    felix.auto.start.1= file:bundle/org.apache.felix.bundlerepository-1.6.2.jar \
    file:bundle/org.apache.felix.gogo.command-0.8.0.jar \
    file:bundle/org.apache.felix.gogo.runtime-0.8.0.jar \
    file:bundle/org.apache.felix.gogo.shell-0.8.0.jar \
    file:bundle/weld-osgi-core-extension-1.0-SNAPSHOT.jar \
    file:bundle/weld-osgi-core-integration-1.0-SNAPSHOT.jar
  • Try this new configuration

    ____________________________
    Welcome to Apache Felix Gogo
    
    g! lb
    START LEVEL 1
       ID|State      |Level|Name
        0|Active     |    0|System Bundle (3.2.2)
        1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
        2|Active     |    1|Apache Felix Gogo Command (0.8.0)
        3|Active     |    1|Apache Felix Gogo Runtime (0.8.0)
        4|Active     |    1|Apache Felix Gogo Shell (0.8.0)
        5|Active     |    1|Weld-OSGi :: Core :: Extension Impl (1.0.0.SNAPSHOT)
        6|Active     |    1|Weld-OSGi :: Implementation :: Weld Integration (1.0.0.SNAPSHOT)
        7|Resolved   |    1|Weld-OSGi :: Core :: Extension API (1.0.0.SNAPSHOT)
        8|Resolved   |    1|Weld-OSGi :: Core :: Integration API (1.0.0.SNAPSHOT)
        9|Resolved   |    1|Weld-OSGi :: Core :: Mandatory (1.0.0.SNAPSHOT)
    g! 

It is time to test your installation with your first application bean bundle. The goal here is to provide a "Hello World!" (and "Goodbye World!") service and use CDI to inject it into the main class of your bean bundle. It will be the hello-world bundle.

First you need to write down the "Hello World!" service:

Nothing fancy here.

Next you need to write the entry point of your application (i.e the main class of the bean bundle). That is the com.sample.App.java main class

package com.sample;

import com.sample.api.HelloWorld; (1)
import org.osgi.cdi.api.extension.events.BundleContainerEvents; (2)
import javax.enterprise.event.Observes;
import javax.inject.Inject;

public class App {

    @Inject (3)
    HelloWorld helloWorld;

    public void onStartup(@Observes BundleContainerEvents.BundleContainerInitialized event) { (4)
        helloWorld.sayHello();
    }

    public void onShutdown(@Observes BundleContainerEvents.BundleContainerShutdown event) { (5)
        helloWorld.sayGoodbye();
    }
}

You import your service interface (1) and the CDI and Weld-OSGi dependencies (2). You ask CDI for an injection of the HelloWorld service (3). onStartup method(4) and onShutdown method (5) are called when CDI usage is enable for the bean bundle (4) (i.e the bean bundle application can start) or when CDI usage is disable for the bean bundle (5) (i.e the bean bundle application may stop).

Finally you should write the configuration files of your bean bundle:

Your project should now looks like that:

hello-world
      pom.xml
    - src
        - main
            - java
                - com.sample
                  App.java
                    - api
                      HelloWorld.java
                    - impl
                      HelloWorldImpl.java
            - resources
                - META-INF
                  beans.xml
                  hello-world.bnd 

It is time to try out this first bean bundle:

Congratulations, you just use CDI in an OSGi environment thank to Weld-OSGi. When you started your bean bundle Weld-OSGi started to manage it by providing it a Weld container. Once the container was completely started (and so the HelloWorld service injection completed) the onStartup method was called and the bean bundle application started.

This first bean bundle was very simple, is Weld-OSGi really enabling complex CDI usage in bean bundle? This section will pick up the hello-world example again and improve it by:

It will be the hello-world-multilingual bean bundle.

CDI usage limits in bean bundle

Every bean bundle gets its own Weld container from the extension bundle, so the CDI usage may stay within the bean bundle boundary:

Furthermore, Weld-OSGi provides Weld container to a bean bundle when it becomes active in the OSGi environment, so any bundle in another state is not managed by Weld-OSGi. And an active bean bundle has CDI usage available only after the Weld container has initialized. In the same way CDI usage is unavailable once the Weld container has shutdown. That's the reason of onStartup and onShutdown methods from previous section:

These two events are CDI events and may be observed with regular CDI mechanisms.

public void onStartup(@Observes BundleContainerEvents.BundleContainerInitialized event) {
    //CDI usage are available in the bean bundle
}

public void onShutdown(@Observes BundleContainerEvents.BundleContainerShutdown event) {
    //CDI usage are unavailable in the bean bundle
}

Trying to use CDI mechanisms before the BundleContainerEvents.BundleContainerInitialized or after the BundleContainerEvents.BundleContainerShutdown event may result in errors.

First you need to upgrade your HelloWorld service and make it multilingual:

Now you will use CDI interceptor to force the bean bundle to present itself every time he greets the World:

Now the HelloWorld service is a bit more complex and you use several CDI features.

Next you need to update the com.sample.App.java main class

package com.sample;

import com.sample.api.HelloWorld;
import com.sample.api.Language;
import org.osgi.cdi.api.extension.events.BundleContainerEvents;

import javax.enterprise.event.Observes;
import javax.inject.Inject;

public class App {

    @Inject @Language("ENGLISH") (1)
    HelloWorld helloWorldEnglish;

    @Inject @Language("FRENCH") (2)
    HelloWorld helloWorldFrench;

    @Inject @Language("GERMAN") (3)
    HelloWorld helloWorldGerman;

    public void onStartup(@Observes BundleContainerEvents.BundleContainerInitialized event) { (4)
        helloWorldEnglish.sayHello();
        helloWorldFrench.sayHello();
        helloWorldGerman.sayHello();
    }

    public void onShutdown(@Observes BundleContainerEvents.BundleContainerShutdown event) { (5)
        helloWorldEnglish.sayGoodbye();
        helloWorldFrench.sayGoodbye();
        helloWorldGerman.sayGoodbye();
    }
}

You replace the initial HelloWorld service injection by three qualified injection, one for each language (1) (2) (3). You also update onStartup and onShutdown methods to greet and say goodbye in the three languages (4) (5).

Finally you should write the configuration files of your bean bundle:

Your project should now looks like that:

hello-world-multilingual
      pom.xml
    - src
        - main
            - java
                - com.sample
                  App.java
                    - api
                      HelloWorld.java
                      Language.java
                      Presentation.java
                    - impl
                      HelloWorldEnglish.java
                      HelloWorldFrench.java
                      HelloWorldGerman.java
                      PresentationInterceptor.java
            - resources
                - META-INF
                  beans.xml
                  hello-world-multilingual.bnd 

It is time to try out these CDI features in an OSGi environment:

CDI seems to respond perfectly in an OSGi environment, thank to Weld-OSGi. But it is sad to use only one bundle for your application, in the next chapter we will see how Weld-OSGi allow to use OSGi powerfulness coupled with CDI easiness in multi bundles application.

You can now use CDI in an OSGi environment with Weld-OSGi and bean bundles. But Weld-OSGi also provide numerous solution helping you make your multi bundles OSGi application using CDI way.

In this chapter you will see:

  • How to publish your CDI beans as OSGi services

  • How to consume these new services in regular OSGi bundles

  • How to match a auto published qualified CDI bean and a propertied OSGi service

  • How to inject OSGi services in bean bundle

CDI beans can be seen like services, with an interface defining the service contract and one or many implementations performing the service. So Weld-OSGi allows to easily publish your CDI beans from bean bundles as OSGi services. To do so you just to put an annotation on your bean implementation classes, avoiding the whole OSGi publishing process.

Modify the hello-world-multilingual bean bundle to auto publish the HelloWorld services as OSGi services. It will be the hello-world-provider bean bundle.

Update the com.sample.impl.HelloWorldImpl*.java implementation classes

...
@Language("*")
@Publish (1)
public class HelloWorld* implements HelloWorld {
    ...
}

Simply put the Publish annotation on the implementation classes (1) and that is it ! Every time Weld-OSGi finds a CDI bean with the Publish annotation, it registers it as a new OSGi service.

Your project should now looks like that:

hello-world-provider
      pom.xml
    - src
        - main
            - java
                - com.sample
                  App.java
                    - api
                      HelloWorld.java
                      Language.java
                      Presentation.java
                    - impl
                      HelloWorldEnglish.java
                      HelloWorldFrench.java
                      HelloWorldGerman.java
                      PresentationInterceptor.java
            - resources
                - META-INF
                  beans.xml
                  hello-world-provider.bnd 

Try your new hello-world-provider bean bundle in the OSGi environment:

In the next section you will see these new OSGi service in action by consuming them in a second bundle. But before that you will what options Weld-OSGi give when you auto publish OSGi service.

The Publish annotation allows to things:

Create a new regular OSGi bundle that will consume the auto published services of the hello-world-provider bean bundle. It will be the hello-world-consumer bundle.

You need to write the entry point of your bundle (i.e the activator class of the bundle). That is the com.sample.Activator.java main class

package com.sample;

import com.sample.api.HelloWorld; (1)
import org.osgi.framework.BundleActivator; (2)
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

public class Activator implements BundleActivator {

    HelloWorld helloWorld;

    @Override
    public void start(BundleContext context) throws Exception { (3)
        ServiceReference helloWorldReference = context.getServiceReference(HelloWorld.class.getName()); (4)
        helloWorld = (HelloWorld)context.getService(helloWorldReference);
        helloWorld.sayHello(); (5)
    }

    @Override
    public void stop(BundleContext context) throws Exception { (6)
        helloWorld.sayGoodbye(); (7)
    }
}

You import your service interface (1) and the OSGi dependencies (2). You ask the OSGi environment for the HelloWorldservice (4). Then you greet (5) and say goodbye (7) to the World at the start (3) and stop (6) of your bundle.

You should also do a quick update of the com.sample.impl.PresentationInterceptor.java interceptor

...
public class PresentationInterceptor {

    @AroundInvoke
    public Object present(InvocationContext ctx) throws Exception {
...
                if(lang.equals("FRENCH")) {
                    System.out.println("Je suis le bundle hello-world-provider");
                    return null;
                } else if(lang.equals("GERMAN")) {
                    System.out.println("Ich bin das bundle hello-world-provider");
                    return null;
                }
            }
        }
        System.out.println("I am the bundle hello-world-provider");
        return null;
    }
}

Your bean bundle may present itself right.

Finally you write the configuration files of your bundle:

Your project should now looks like that:

hello-world-consumer
      pom.xml
    - src
        - main
            - java
                - com.sample
                  Activator.java
            - resources
                - META-INF
                  hello-world-consumer.bnd 

Try your new hello-world-consumer bean bundle in the OSGi environment:

Now you need to decide what language your consumer bundle will speak. To do so you cannot use CDI qualifier like in provider bundle because you are using OSGi mechanisms to obtain the service instance. Fortunately Weld-OSGi provides a binding between CDI service qualification and OSGi service properties.

Conversion CDI qualifiers to OSGi service properties

A CDI qualifier will generate an OSGi service property for each of its valued element (an element with a default value is always considered valued) following these rules:

Using these rules, modify your hello-world-consumer bundle in order to make it speak the three languages like the hello-world-provider bean bundle. It will be the hello-world-consumer-multilingual bundle.

All the work happens in the com.sample.Activator.java main class

package com.sample;

import com.sample.api.HelloWorld; (1)
import org.osgi.framework.BundleActivator; (2)
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

public class Activator implements BundleActivator {

    HelloWorld helloWorldEnglish;
    HelloWorld helloWorldFrench;
    HelloWorld helloWorldGerman;

    @Override
    public void start(BundleContext context) throws Exception { (3)
        ServiceReference helloWorldEnglishReference = context.getServiceReferences(HelloWorld.class.getName(),"(language.value=ENGLISH)")[0]; (4)
        ServiceReference helloWorldFrenchReference = context.getServiceReferences(HelloWorld.class.getName(),"(language.value=FRENCH)")[0];
        ServiceReference helloWorldGermanReference = context.getServiceReferences(HelloWorld.class.getName(),"(language.value=GERMAN)")[0];

        helloWorldEnglish = (HelloWorld)context.getService(helloWorldEnglishReference);
        helloWorldFrench = (HelloWorld)context.getService(helloWorldFrenchReference);
        helloWorldGerman = (HelloWorld)context.getService(helloWorldGermanReference);

        helloWorldEnglish.sayHello(); (5)
        helloWorldFrench.sayHello();
        helloWorldGerman.sayHello();
    }

    @Override
    public void stop(BundleContext context) throws Exception { (6)
        helloWorldEnglish.sayGoodbye(); (7)
        helloWorldFrench.sayGoodbye();
        helloWorldGerman.sayGoodbye();
    }
}

You import your service interface (1) and the OSGi dependencies (2). You ask the OSGi environment for the HelloWorldservices specifying the correct filter (4). Then you greet (5) and say goodbye (7) to the World at the start (3) and stop (6) of your bundle.

Your project should now looks like that:

hello-world-consumer-multilingual
      pom.xml
    - src
        - main
            - java
                - com.sample
                  Activator.java
            - resources
                - META-INF
                  hello-world-consumer-multilingual.bnd 

Try your new hello-world-consumer-multilingual bean bundle in the OSGi environment:

You can now use auto published service from a bean bundle in any other bundle. It opens CDI features to regular OSGi bundles and ensure the compatibility of Weld-OSGi with old OSGi application.

But the OSGi looking process for services is still a complicated, in the next section you will see how you can use CDI programming in order to get your OSGi services with Weld-OSGi.

Create a new bean bundle that will use the auto published services by injection. It will be the hello-world-consumer2-multilingual bean bundle.

The entry point of your bean bundle, the com.sample.App.java main class

package com.sample;

import com.sample.api.HelloWorld;
import com.sample.api.Language;
import org.osgi.cdi.api.extension.Service;
import org.osgi.cdi.api.extension.annotation.OSGiService;
import org.osgi.cdi.api.extension.events.BundleContainerEvents;

import javax.enterprise.event.Observes;
import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Inject;

public class App {

    @Inject (1)
    @OSGiService
    HelloWorld helloWorld;

    @Inject (2)
    Service<HelloWorld> helloWorldService;

    @Inject (3)
    @OSGiService
    @Language("ENGLISH")
    HelloWorld helloWorldEnglish;

    @Inject
    Service<HelloWorld> helloWorldServiceEnglish;

    @Inject
    @OSGiService
    @Language("FRENCH")
    HelloWorld helloWorldFrench;

    @Inject
    Service<HelloWorld> helloWorldServiceFrench;

    @Inject
    @OSGiService
    @Language("GERMAN")
    HelloWorld helloWorldGerman;

    @Inject
    Service<HelloWorld> helloWorldServiceGerman;

    HelloWorld helloWorld2;
    HelloWorld helloWorldEnglish2;
    HelloWorld helloWorldFrench2;
    HelloWorld helloWorldGerman2;

    public void onStartup(@Observes BundleContainerEvents.BundleContainerInitialized event) { (4)
        helloWorld2 = helloWorldService.get(); (5)
        helloWorldEnglish2 = helloWorldServiceEnglish.select(new LanguageAnnotationEnglish()).get(); (6)
        helloWorldFrench2 = helloWorldServiceFrench.select("(language.value=FRENCH)").get(); (7)
        helloWorldGerman2 = helloWorldServiceGerman.select("(language.value=GERMAN)").get();

        helloWorld.sayHello(); (8)
        helloWorld2.sayHello();
        helloWorldEnglish.sayHello();
        helloWorldEnglish2.sayHello();
        helloWorldFrench.sayHello();
        helloWorldFrench2.sayHello();
        helloWorldGerman.sayHello();
        helloWorldGerman2.sayHello();

        for (HelloWorld service : helloWorldService) { (9)
            service.sayHello();
        }
    }

    public void onShutdown(@Observes BundleContainerEvents.BundleContainerShutdown event) { (10)
        helloWorld.sayGoodbye(); (11)
        helloWorld2.sayGoodbye();
        helloWorldEnglish.sayGoodbye();
        helloWorldEnglish2.sayGoodbye();
        helloWorldFrench.sayGoodbye();
        helloWorldFrench2.sayGoodbye();
        helloWorldGerman.sayGoodbye();
        helloWorldGerman2.sayGoodbye();

        for (HelloWorld service : helloWorldService) {
            service.sayGoodbye();
        }
    }

    private class LanguageAnnotationEnglish extends AnnotationLiteral<Language> implements Language {
        @Override
        public String value() {
            return "ENGLISH";
        }
    }
}

A lot of things to discuss here. There is two ways to get an OSGi service injected:

If you want to choose the implementation:

Finally you say hello (8) and goodbye (11) when its right (4) (10) in all languages with all technique.

Same old configuration files:

Your project should now looks like that:

hello-world-consumer2-multilingual
      pom.xml
    - src
        - main
            - java
                - com.sample
                  App.java
            - resources
                - META-INF
                  beans.xml
                  hello-world-consumer2-multilingual.bnd 

Try your new hello-world-consumer2-multilingual bean bundle in the OSGi environment:

You know now how to use the OSGi service layer using Weld-OSGi. Howover you may refer to the specification to specific usage and niceties. In the next chapters you will see what other things Weld-OSGi can do, helping you using OSGi framework for your application:

Weld-OSGi is enabling CDI in bean bundles, so you can use CDI event notification in your bean bundles. But Weld-OSGi also provide the support of OSGi framework events through CDI event mechanisms. And following the same principle Weld-OSGi also allows a full uncouple communication between bean bundles based on CDI events.

In this chapter you will see:

  • How to fire and observe OSGi framework and Weld-OSGi events in bean bundles

  • How to send and receive inter-bundle communication between your bean bundles

From here you will create a new application based on bean bundles. So far your bundles were greeting and saying goodbye, let them be a bit more interactive. You will have three bean bundles that present themselves when they start and greet newcomers (and say goodbye to leavers) when they start (or stop).

Create your three bean bundles following this scheme. They will be the welcoming-tom, welcoming-dick and welcoming-harry bean bundles.

First write the com.sample.App main classes:

package com.sample;

import org.osgi.cdi.api.extension.events.BundleContainerEvents;
import org.osgi.cdi.api.extension.events.BundleEvents;

import javax.enterprise.event.Observes;

public class App {

    public void onStartup(@Observes BundleContainerEvents.BundleContainerInitialized event) { (1)
        System.out.println("Tom: Hi everyone!");
    }

    public void onShutdown(@Observes BundleContainerEvents.BundleContainerShutdown event) { (2)
        System.out.println("Tom: Bye everyone!");
    }

    public void greetNewcomer(@Observes BundleEvents.BundleStarted event) { (3)
        String name = event.getSymbolicName().substring(21, event.getSymbolicName().length()); (4)
        if (!name.equals("tom")) { (5)
            System.out.println("Tom: Welcome " + name +'!');
        }
    }

    public void sayGoodbyeToLeaver(@Observes BundleEvents.BundleStopped event) { ((6)
        String name = event.getSymbolicName().substring(21, event.getSymbolicName().length()); (7)
        if (!name.equals("tom")) { (8)
            System.out.println("Tom: Goodbye " + name +'!');
        }
    }
}

You monitor four different Weld-OSGi events, two events about the CDI life cycle (your entry point from the previous chapter) (1) (2) an two events about the bundle life cycle (from the OSGi framework) (3) (6). It allows to perform actions when the bean bundle is started (both for OSGi and CDI point of view) (1) or stopped (2). Here you just greet or say goodbye. When a bundle (every bundle) starts (3) or stops (6) you get its name (4) (7) and say the appropriate sentence to other bundle (5) (8). Do not forget to change the name accordingly to the current bundle !

Now configure your three bean bundles:

Your three projects should now looks like that:

welcoming-*
      pom.xml
    - src
        - main
            - java
                - com.sample
                  App.java
            - resources
                - META-INF
                  beans.xml
                  welcoming-*.bnd

Try everything out:

You can now use inter bundle notification in order to make your bean bundles aware of the other bundles. But the choice of events seems a bit limited, more or less is about bundle (and bean bundle) and service life cycle. But what if you want to fire and listen custom events ?

Weld-OSGi allows it with its InterBundleEvent events. In this section you will update your three bean bundles to make them chat even when no movement is occurring. For example your bean bundles can ask if the others are still here on regular basis.

Update your three bean bundles following this scheme. They will be the talkative-tom, talkative-dick and talkative-harry bean bundles.

Update the com.sample.App main classes:

package com.sample;

import org.osgi.cdi.api.extension.annotation.Sent;
import org.osgi.cdi.api.extension.annotation.Specification;
import org.osgi.cdi.api.extension.events.BundleContainerEvents;
import org.osgi.cdi.api.extension.events.BundleEvents;
import org.osgi.cdi.api.extension.events.InterBundleEvent;
import org.osgi.framework.Bundle;

import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.inject.Inject;

public class App {

    @Inject
    private Event<InterBundleEvent> communication; (1)

    public void onStartup(@Observes BundleContainerEvents.BundleContainerInitialized event) { (2)
        System.out.println("Harry: Hi everyone!");
        AskThread askThread = new AskThread(communication, event.getBundleContext().getBundle()); (3)
        askThread.start();
    }

    public void onShutdown(@Observes BundleContainerEvents.BundleContainerShutdown event) { (4)
        System.out.println("Harry: Bye everyone!");
    }

    public void greetNewcomer(@Observes BundleEvents.BundleStarted event) { (5)
        String name = event.getSymbolicName().substring(21, event.getSymbolicName().length());
        if (!name.equals("harry")) {
            System.out.println("Harry: Welcome " + name + '!');
        }
    }

    public void sayGoodbyeToLeaver(@Observes BundleEvents.BundleStopped event) { (6)
        String name = event.getSymbolicName().substring(21, event.getSymbolicName().length());
        if (!name.equals("harry")) {
            System.out.println("Harry: Goodbye " + name + '!');
        }
    }

    public void acknowledge(@Observes @Sent @Specification(String.class) InterBundleEvent message) { (7)
        System.out.println("Harry: Hey " + message.get() + " i'm still here.");
    }

    private class AskThread extends Thread { (8)
        Event<InterBundleEvent> communication;
        Bundle bundle;

        AskThread(Event<InterBundleEvent> communication, Bundle bundle) {
            this.communication = communication;
            this.bundle = bundle;
        }

        public void run() {
            while(true) { (9)
                try {
                    sleep(5000);
                } catch (InterruptedException e) {
                }
                if(bundle.getState() == Bundle.ACTIVE) { (10)
                    System.out.println("Harry: is there still someone here ?");
                    communication.fire(new InterBundleEvent("harry")); (11)
                } else {
                    break;
                }
            }
        }
    }
}

There is no modification for the previous chat action (2) (4) (5) (6); except that you start a thread when the bean bundle has started (3). This thread (8) is an infinite loop (9) that ask the active bundle to acknowledge there presence by firing an InterBundleEvent (11). This InterBundleEvent is listened by your three bean bundles in order to print the answer. The listening method catch only communication from outside the bean bundle (@Sent) and that has a String message (@Specification(String.class)) (7).

There is nothing to update in the bean bundles configuration files.

Your three projects should now looks like that:

talkative-*
      pom.xml
    - src
        - main
            - java
                - com.sample
                  App.java
            - resources
                - META-INF
                  beans.xml
                  talkative-*.bnd

Install everything and let your bundle chat:

____________________________
Welcome to Apache Felix Gogo

g! lb
START LEVEL 1
   ID|State      |Level|Name
    0|Active     |    0|System Bundle (3.2.2)
    1|Active     |    1|Apache Felix Bundle Repository (1.6.2)
    2|Active     |    1|Apache Felix Gogo Command (0.8.0)
    3|Active     |    1|Apache Felix Gogo Runtime (0.8.0)
    4|Active     |    1|Apache Felix Gogo Shell (0.8.0)
    5|Active     |    1|Weld-OSGi :: Core :: Extension Impl (1.0.0.SNAPSHOT)
    6|Active     |    1|Weld-OSGi :: Implementation :: Weld Integration (1.0.0.SNAPSHOT)
    7|Resolved   |    1|Weld-OSGi :: Core :: Extension API (1.0.0.SNAPSHOT)
    8|Resolved   |    1|Weld-OSGi :: Core :: Integration API (1.0.0.SNAPSHOT)
    9|Resolved   |    1|Weld-OSGi :: Core :: Mandatory (1.0.0.SNAPSHOT)
   10|Installed  |    1|talkative-dick (1.0.0)
   11|Installed  |    1|talkative-harry (1.0.0)
   12|Installed  |    1|talkative-tom (1.0.0)
g! start 10 11 12
Dick: Hi everyone!
Harry: Hi everyone!
Dick: Welcome harry!
Tom: Hi everyone!
Dick: Welcome tom!
Harry: Welcome tom!
g! Dick: is there still someone here ?
Harry: Hey dick i'm still here.
Tom: Hey dick i'm still here.
Harry: is there still someone here ?
Dick: Hey harry i'm still here.
Tom: Hey harry i'm still here.
Tom: is there still someone here ?
Dick: Hey tom i'm still here.
Harry: Hey tom i'm still here.
Dick: is there still someone here ?
Harry: Hey dick i'm still here.
Tom: Hey dick i'm still here.
Harry: is there still someone here ?
Dick: Hey harry i'm still here.
Tom: Hey harry i'm still here.
Tom: is there still someone here ?
Dick: Hey tom i'm still here.
Harry: Hey tom i'm still here.
stop 10
Dick: Bye everyone!
Tom: Goodbye dick!
Harry: Goodbye dick!
g! stop 11
Harry: Bye everyone!
Tom: Goodbye harry!
g! stop 12
Tom: Bye everyone!
g! 

You can play with your bean bundles, looking them chat with each other. The InterBundleEvent allow you to fire any object you want, so it is a powerful communication system between your bean bundle. You may refer to the Weld-OSGi specifications for a complete review of InterBundleEvent usage.

Weld-OSGi do not fordid you to use classic OSGi mechanisms. More it give you some way to easily get main OSGi object like Bundle or BundleContext. You just inject them, don't need to use OSGi verbosity.

There are :