SeamFramework.orgCommunity Documentation
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 !
Weld-OSGi broadcast five types of events, two for OSGi framework events, two for CDI events and one for bean bundle communications.
OSGi events monitor:
Bundle life cycle events. They all respect the
AbstractBundleEvent
abstract class:
BundleEvents.BundleInstalled
BundleEvents.BundleLazyActivation
BundleEvents.BundleResolved
BundleEvents.BundleStarted
BundleEvents.BundleStarting
BundleEvents.BundleStopped
BundleEvents.BundleStopping
BundleEvents.BundleUninstalled
BundleEvents.BundleUnresolved
BundleEvents.BundleUpdated
Service life cycle events. They all respect the
AbstractServiceEvent
abstract class:
ServiceEvents.ServiceArrival
ServiceEvents.ServiceChanged
ServiceEvents.ServiceDeparture
CDI events monitor.
Bean bundle CDI containers life cycle. They all respect the
AbstractBundleContainerEvent
abstract class:
BundleContainerEvents.BundleContainerInitialized
BundleContainerEvents.BundleContainerShutdown
Bean bundle service dependency validation:
Valid
Invalid
Communication events broadcast message between bean bundle:
InterBundleEvent
Each type of event carries its own set of information and has its own range, please refer to the Weld-OSGi specification for more information.
Be careful when you use Weld-OSGi in order to handle OSGi events, you are still using CDI mechanisms. Thus when an event is observed it generate a contextual instance of the bean that declares the observing method. Class state might be different between calls.
Now configure your three bean bundles:
The pom.xml
Maven configuration
file
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sample</groupId> <artifactId>welcoming-*</artifactId> <version>1.0</version> <packaging>bundle</packaging> <dependencies> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> <dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> <version>1.0-SP4</version> </dependency> <dependency> <groupId>org.osgi.cdi</groupId> <artifactId>weld-osgi-core-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <extensions>true</extensions> <configuration> <instructions> <_include>-target/classes/META-INF/${project.artifactId}.bnd</_include> </instructions> </configuration> </plugin> </plugins> </build> </project>
Just
put the right artifactId
here.
The welcoming-*.bnd
OSGi configuration
file
# Let bnd handle the MANIFEST.MF generation
Here
it is the file name that may match the artifactId
.
The META-INF\beans.xml
CDI marker
file:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> </beans>
Nothing to say !
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:
Build your project,copy the generated files and update the Felix configuration ... you know the deal.
Play with your three bean bundles
____________________________ 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|welcoming-dick (1.0.0) 11|Installed | 1|welcoming-harry (1.0.0) 12|Installed | 1|welcoming-tom (1.0.0) g! start 10 Dick: Hi everyone! g! start 11 Harry: Hi everyone! Dick: Welcome harry! g! start 12 Tom: Hi everyone! Harry: Welcome tom! Dick: Welcome tom! g! stop 10 Dick: Bye everyone! Tom: Goodbye dick! Harry: Goodbye dick! g! start 10 Dick: Hi everyone! Tom: Welcome dick! Harry: Welcome dick! g! stop 12 Tom: Bye everyone! Harry: Goodbye tom! Dick: Goodbye tom! g! stop 11 Harry: Bye everyone! Dick: Goodbye harry! g! stop 10 Dick: Bye everyone! g! start 10 Dick: Hi everyone! g! start 11 Harry: Hi everyone! Dick: Welcome harry! g! start 12 Tom: Hi everyone! Dick: Welcome tom! Harry: Welcome tom!
You can now make interactive application using multiple bean bundles and CDI event mechanisms.
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.