The bundle structure
As already mentioned in the first tutorial, bundles are packaged in JAR files. Inside a JAR, the files are organized with the following structure:
+- META-INF
| +- MANIFEST.MF
|
+- OSGI-INF
| +- RunnableProvider.xml
|
+- cy
+- ac
+- ucy
+- cs
+- osgi
+- tutorial2
+- RunnableProvider.class
This structure contains the Java classes (i.e., in the "cy.ac.ucy.cs.osgi.tutorial.*" package structure) along with the configuration data of the bundle (i.e., "META_INF/MANIFEST.MF") and of the component (i.e., "OSGI-INF/RunnableProvider.xml"). We will study these parts one by one.The implementation code
In this tutorial, we develop a very simple component, offering a very simple service. The source code for the implementing class looks as follows:
package cy.ac.ucy.cs.osgi.tutorial2;
public class RunnableProvider implements Runnable
{
public void run()
{
System.out.println("RunnableProvider says hi!");
}
}
This simple class implements the "java.lang.Runnable" interface, which specifies a single method: "public void run()". In this example we provide the most simple (and useless) implementation, just to illustrate how Declarative Services work. When the service is invoked, a message is printed in the console where the "RunnableProvider" is deployed.It is worth noting that this class is a Plain Old Java Object (POJO), and thus requires no additional libraries for compiling it. But, in order to become OSGi deployable, and Declarative Services recognizable, this component must be accompanied with the appropriate metadata.
The service descriptor
As a Declarative Services component, the RunnableProvider must be accompanied by an appropriate service descriptor, as the one illustrated in the following:
<component name="RunnableProvider"></component>
<implementation class="cy.ac.ucy.cs.osgi.tutorial2.RunnableProvider"/>
<service>
<provide interface="java.lang.Runnable"/>
</service>
</component>
This file, which we named "RunnableDescriptor.xml" in this example, is expressed in XML and is used to specify the defined component, along with any provided (and as we will later on, required) services.In this case, the component is named "RunnableProvider" and its implementation is provided by the class we specified already: "cy.ac.ucy.cs.osgi.tutorial2.RunnableProvider". Furthermore, this component provides a service, as it is specified by the "java.lang.Runnable" interface.
In real applications, the provided services correspond to more complex, custom interfaces. However, in this case we chose an interface which is standard in the JRE, so that we do not have to export/import any classes at this point (this will be presented in another tutorial).
The bundle manifest
Finally, the last piece that is needed to make the bundle deployable is the bundle manifest. This file describes the library dependencies of the bundle (imported and exported packages), the name and version of the bundle and a reference to the service descriptor.
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Tutorial 2: Runnable provider
Bundle-SymbolicName: RunnableProvider
Bundle-Version: 1.0.0
Service-Component: OSGI-INF/RunnableProvider.xml
(Important: Please make sure that you add an empty line at the end of every MANIFEST file you define, because otherwise you risk that the parser will truncate the last line of your file.)Most of the properties in this bundle descriptor are self-explanatory. The last parameter points to the corresponding service descriptor, inside the JAR package. Finally, in this example, there are no imported or exported packages.
To produce the required file, simply compile the Java class and package everything together in a JAR file with the structure described above. A version of such a JAR file is available here. It is also possible to automate building such bundles using ANT or MAVEN. An example ANT build script is included in the RunnableProvider JAR file. Furthermore, the same JAR file includes a copy of the RunnableProvider's Java source code.
Deploying and starting your first component
Once you have produced the JAR-packaged bundle, the next step is to deploy it. Following the same approach as the one described in the first tutorial, you can install and start the RunnableProvider bundle:
osgi> install file:RunnableProvider.jar
Bundle id is 4
osgi> start 4
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.2.R34x_v20080826-1230
1 ACTIVE org.eclipse.equinox.ds_1.0.0.v20080427-0830
2 ACTIVE org.eclipse.equinox.util_1.0.0.v20080414
3 ACTIVE org.eclipse.osgi.services_3.1.200.v20071203
4 ACTIVE RunnableProvider_1.0.0
osgi> services (objectClass=java.lang*)
{java.lang.Runnable}={component.name=RunnableProvider, component.id=0, service.id=26}
Registered by bundle: file:RunnableProvider.jar [4]
No bundles using service.
The "services" command results to the system displaying all services registered by any components. As those services might be numerous though, we use a filtering option ("services (objectClass=java.lang*)". This filter blocks any services that do not start with a "java.lang" package prefix.For testing purposes, you can then stop the RunnableProvider bundle and issue the same "services" command a second time. You will then realize that the "java.lang.Runnable" service is not offered anymore.
Homework 2.1: After you deploy and start your component, as explained in this tutorial, test again the commands that you have investigated in Homework 1.1 (Tutorial 1).
Homework 2.2: Read the second chapter (First Steps in OSGi) of Neil Bartlett's book. You can skip sections 2.2, 2.3, 2.4, 2.5 and 2.6. You can also skip sections 2.9 and 2.10 for now (they will be covered in follow-up tutorials).
4 comments:
I think there is a bug in the xml file syntax. Specifically, you are closing the component tag twice, once in the first line and once in the last line.
Thanx
You are right. The first one is there by mistake.
Corrected this by deleting the first "</component>" tag.
Thanks for pointing this out.
I think that the name of the xml file should be RunnableProvider.xml and not RunnableDescriptor.xml, to match the name in the manifest file.
Thank you Yiota, you are right. I have updated the JAR file.
Post a Comment