Thursday, August 28, 2008

Sling OSGi Track pt 1: hand-rolled service bundle

Technorati Tags: ,,

This is the first in a series that tries to show how to create OSGi bundles for sling.

I'll create a very simple service that answers with "hello" when asked to say hello.
This is little functionality, but demonstrates how to get the tools ready for creating CRX bundles.

Aims:

  • create a service that returns the String "hello" when called with sayHello()
  • use maven for building

Ingredients:

  • CRX-quickstart

Files:

Outline:

  • Project structure
  • Define the service interface
  • Create an implementation of that interface
  • Create an Activator that registers the service
  • Create the Manifest
  • Create the Maven pom
  • Build
  • Install
  • Create a test client

Execution:

Project structure
.
|-- pom.xml
`-- src
    `-- main
        |-- java
        |   `-- mh
        |       `-- osgitest
        |           |-- Activator.java
        |           |-- SampleService.java
        |           `-- SampleServiceImpl.java
        `-- resources
            `-- META-INF
                `-- MANIFEST.MF
Define the service interface

The service interface is straightforward: it contains a single public method.

  1: package mh.osgitest;
  2: 
  3: public interface SampleService {
  4: 	public String sayHello();
  5: }
Create an implementation of that interface

This is just as easy and pojo:

  1: package mh.osgitest;
  2: 
  3: public class SampleServiceImpl implements SampleService {
  4: 	public String sayHello() {
  5: 		return "hello";
  6: 	}
  7: }
  8: 
Create an activator that registers the service

Every OSGi bundle must have an activator that implements the BundleActivator interface.
(simplification. declarative services do not need an activator).

The BundleActivator gives us start and stop methods that will be called when the bundles is started / stopped by the container.
In the start method, the service instance is created (11), and then registered. The registerService method of the BundleContext receives the class name under which the service is registered and by which it can be located (14), the service instance (15) and an empty configuration table.

  1: package mh.osgitest;
  2: 
  3: import java.util.Hashtable;
  4: import org.osgi.framework.BundleActivator;
  5: import org.osgi.framework.BundleContext;
  6: 
  7: public class Activator implements BundleActivator {
  8: 
  9: 	public void start(BundleContext context) throws Exception {
 10: 
 11: 		SampleService sample = new SampleServiceImpl();
 12: 
 13: 		context.registerService(
 14: 				SampleService.class.getName(), 
 15: 				sample,
 16: 				new Hashtable<Object, Object>());
 17: 
 18: 		System.err.println("SampleService Started");
 19: 	}
 20: 
 21: 	public void stop(BundleContext context) throws Exception {
 22: 		System.err.println("SampleService Stopped");
 23: 	}
 24: }
Create the Manifest

The manifest file needs some OSGi specific entries:

  1: Manifest-Version: 1.0
  2: Bundle-ManifestVersion: 2
  3: Bundle-Name: Simple OSGITest
  4: Bundle-SymbolicName: mh.osgitest
  5: Bundle-Version: 1.0.0
  6: Bundle-Activator: mh.osgitest.Activator
  7: Bundle-Vendor: Moritz Havelock
  8: Import-Package: org.osgi.framework;version="1.3.0"
  9: Export-Package: mh.osgitest;version=0.0.1
 10: Bundle-ClassPath: .


(3) Name of the Bundle. Choose freely
(4) The symbolic name by which the bundle is referred to.
(6) the activator is the name of the class that implements BundleActivator
(8) Import-Package declares the packages that this bundle expects to be provided by other packages.
(9) Export-Package declares the package that is exposed and available to other bundles.

Create the Maven pom

The only things needed (except for dependencies) are

  • configuring our own manifest file to be blended in when bundling the jar file and
  • setting source style to Java 5
  1: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2: 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  3: 	<modelVersion>4.0.0</modelVersion>
  4: 	<groupId>mh.studies</groupId>
  5: 	<artifactId>mh.studies.sling.osgitest</artifactId>
  6: 	<name>OSGI Test Bundle</name>
  7: 	<version>0.0.1</version>
  8: 	<description />
  9: 	<build>
 10: 		<plugins>
 11: 			<plugin>
 12: 				<groupId>org.apache.maven.plugins</groupId>
 13: 				<artifactId>maven-jar-plugin</artifactId>
 14: 				<version>2.2</version>
 15: 				<configuration>
 16: 					<archive>
 17: 						<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
 18: 					</archive>
 19: 				</configuration>
 20: 			</plugin>
 21: 			<plugin>
 22: 				<groupId>org.apache.maven.plugins</groupId>
 23: 				<artifactId>maven-compiler-plugin</artifactId>
 24: 				<configuration>
 25: 					<source>1.5</source>
 26: 					<target>1.5</target>
 27: 				</configuration>
 28: 			</plugin>
 29: 		</plugins>
 30: 	</build>
 31: 	<dependencies>
 32: 		<dependency>
 33: 			<groupId>org.apache.felix</groupId>
 34: 			<artifactId>org.osgi.core</artifactId>
 35: 			<version>1.0.1</version>
 36: 		</dependency>
 37: 	</dependencies>
 38: </project>
Build
mvn clean package
Install

To install the bundle, go to the system console at http://localhost:7402/system/console/list.
(note that the system console does not fully work in Internet Explorer)

Hit the "Browse" button and select the jar file from the target/ directory created by maven.

Check the "Start" box, level the level at 20 and hit "Install or Update".

Then, hit "Refresh Package". You will then see an entry "Simple OSGITest" in the list of bundles. Click it to see an expanded view.
You will see the Bundle properties, plus the registered service of type mh.osgitest.SampleService.

SimpleOSGI-expanded

Create a test client

In the CRX browser, create a node /content/test of type nt:unstructured, and give it a property "sling:resourceType" with a value of "samples:osgitest".
Create the structure /apps/samples/osgitest, and there create the file GET.esp with the following contents.

In line 3, the service is obtained from the sling helper object.

  1: <%
  2: var service =
  3:   sling.getService(Packages.mh.osgitest.SampleService);
  4:   
  5: %><%= service.sayHello() %>

Now, you can use a browser or curl to call that URL with an impressing result ;-)

D:\projekte\workspace-sling\mh.studies.sling.osgitest>curl http://localhost:7402/test
hello

No comments: