BlueprintHelloWorldTutorial
Blueprint tutorial
Introduction
This tutorial is designed for people who are starting to use the Apache Aries Blueprint implementation. After you have worked through the tutorial you will
-
be able to run a very simple piece of code in the Aries Blueprint container
-
understand bean, service and reference definitions in Blueprint
The tutorial assumes a basic working knowledge of Java development, Eclipse and some understanding of OSGi.
In order to work through the tutorial you will need to do checkout and build copy of Aries, the instructions are here . This tutorial assumes that you have built Aries and imported the samples/helloworld projects into Eclipse.
The API, Server and Client projects
When you have checked out and built the Aries code your workspace will contain the four projects highlighted in the picture below. This is a screen shot taken from my Eclipse package explorer: The project called org.apache.aries.samples.helloworld.blueprint.assembly contains no Java code and is just used to pull together the minimal OSGi platform that is needed to run the sample. Expanding the org.apache.aries.samples.helloworld.blueprint.api project shows this: There are two interesting features of this project, the HelloWorldService.java interface and empty META-INF directory. HelloWorldService.java is the interface for the Helloworld service. It is good OSGi practice to keep interfaces and implementation classes in separate bundles. This allows implementations to be replaced independently of their interfaces. The META-INF directory is where you would expect to see a file called MANIFEST.MF. You don’t see it because we are using a Maven plugin (look at the pom.xml) to generate the bundle manifest automatically.
Expanding the org.apache.aries.samples.helloworld.blueprint.server project shows There are again two interesting files. HelloWorldServiceImpl.java is an implementation of the HelloWorldService interface in the first blueprint-helloworld-api project. The file config.xml is the Blueprint configuration for this package.
The org.apache.aries.samples.helloworld.blueprint.client project looks like this The client implementation is in HelloWorldClient.java. The file config.xml contains the Blueprint for the client.
The Blueprint XML
Blueprint xml files contain all the information that the Blueprint runtime needs to internally wire a bundle’s components. They also contain the information that the Blueprint runtime needs to register and locate services in the OSGi service registry. This allows for service-based interactions between bundles.
This is a view of what the xml in the two config.xml files is describing: image::documentation/tutorials/BPTutorial5F.png[hw5]
The client configuration file has one bean definition which names the Java class that it requires and gives the name of the method that will be run when the bean has been initialised. The bean definition also describes a property, helloWorldService, which points (see the arrow) to the reference definition. This is telling Blueprint that the bean (helloclient) needs the container to supply a service matched by the 'helloservice' reference, which in turns specifies the interface to be implemented by that service.
The server configuration file is similar - with one bean definition which points to the Java class that implements HelloWorldService. The second element in this file is the service definition. This registers a service under the HelloWorldService interface, implemented by the 'helloservice' bean.
The Java classes
Both the Java classes are very simple, there are just a couple of minor points to make about each one. The HelloWorldClient class looks like this: image::documentation/tutorials/BPTutorial8F.png[hw8]
-
The setHelloWorldService() method will be called by the Blueprint container in order to inject an object implementing the HelloWorldService interface.
-
The startUp() method will be run when the bundle is started: remember that this was specified in the Blueprint. This method executes a hello() method which must be supplied by an implementation of HelloWorldService. The startUp() method in this case will only be run after dependencies have been injected. This is the default Blueprint behaviour.
The HelloWorldServiceImpl class is even simpler. It has two methods: image::documentation/tutorials/BPTutorial9F.png[hw9]
-
A startUp() method which writes a message to say that the bundle is being started
-
A hello() method which writes a 'hello' message
Running the code
The code can be run on an Equinox (or Felix) framework. The org.apache.aries.samples.helloworld.blueprint.assembly package assembles an Equinox based platform that contains all of the OSGi bundles you need. To start it up go to the target directory in org.apache.aries.samples.helloworld.blueprint.assembly, and from command line, type:
java -jar osgi-3.5.0.v20090520.jar -console
You will see some messages, after which you should get the 'osgi>' prompt; sometimes you will need to press return to see it. At the prompt, type 'ss' to see the status of the bundles: image::documentation/tutorials/BPTutorial10.png[hw10] Next, start the Blueprint container bundle by typing 'start 5' at the osgi prompt. You will see many debug messages in the code, this is because the target/configuration/config.ini specifies the message level to be DEBUG, if there are too many messages you can change this to 'INFO'. The debug messages are quite interesting to look through in themselves, but a little beyond the scope of this tutorial. The last debug message should indicate that a Blueprint container is running in state 'created'. After that, start the blueprint-helloworld-api in the same way by typing 'start 6' at the prompt.
The next step is to start the blueprint-helloworld-server bundle. In amongst the DEBUG messages you should see the single line of output from the startUp() method if the HelloWorldServiceImpl class:
======>>> Starting HelloWorld Server
At this point it is possible to see if the HelloWorldService is registered, like this:
osgi> services (objectClass=org.apache.aries.samples.blueprint.helloworld.api.HelloWorldService)
running this command will tell you that a service is registered but that nothing is using it.
Finally, start the blueprint-helloworld-client bundle. If things have gone according to plan you should see a sequence of 3 messages from the startUp() method, the second message will be a 'hello' from HelloWorldService:
========>>>>Client HelloWorld: About to execute a method from the Hello World server ======>>> A message from the server: Hello World! ========>>>>Client HelloWorld: ... if you didn't just see a Hello World message something went wrong
If you re-run the services command above it will tell you that the blueprint-helloworldclient bundle is using the blueprint-helloworldservice.
One interesting experiment is to start the blueprint-helloworldclient bundle before the blueprint-helloworldserver bunde. When you do this, you will see no output until the second bundle is started because the 'helloclient' bean cannot be initialised until that point. If you wait more than five minutes by default, there will be a timeout and the client will not be initialised at all.
Summary
In the tutorial you have seen how to construct three simple Blueprint bundles. The client bundle depends directly on the api and indirectly on the server bundle. Blueprint takes care of registering a service from the server bundle so that the client bundle can use it. You will have some appreciation of the classes and XML that form a Blueprint application, and you have seen a simple example working. Of course, this tutorial barely touches on many of the features provided by the Aries Blueprint implementation. Anyone keen to explore the features of Blueprint should look at this article and continue by reading the [OSGi specification|http://www.osgi.org/Download/Release4V42] (see the 4.2 Compendium spec, section 121, "Blueprint Container Specification") and making modifications to the sample code.