Friday, August 29, 2008

Sling OSGi Track pt 4: installing to Sling using Maven

This is the continuation of

In this part, I will show how to install a maven-built bundle to sling directly from maven

Aims:

  • Show how to install a maven-built bundle to sling

Ingredients:

Files:

Outline:

  • Add the sling plugin to the pom
  • Add the ASF incubating repository
  • Build and Install
  • Test

Execution:

Add the sling plugin to the pom

Add the following snippet to the build plugins.

(8-10) bind the execution of the plugin's install-bundle goal to install phase goal
(11-15) configure the sling URL to use, the username and the password.

  1: <plugin>
  2: 	<groupId>org.apache.sling</groupId>
  3: 	<artifactId>maven-sling-plugin</artifactId>
  4: 	<version>2.0.2-incubator</version>
  5: 	<executions>
  6: 		<execution>
  7: 			<id>install-bundle</id>
  8: 			<goals>
  9: 				<goal>install</goal>
 10: 			</goals>
 11: 			<configuration>
 12: 				<slingUrl>http://localhost:7402/system/console/install</slingUrl>
 13: 				<user>admin</user>
 14: 				<password>admin</password>
 15: 			</configuration>
 16: 		</execution>
 17: 	</executions>
 18: </plugin>
Add the ASF incubating repository

The sling plugin (to date) lives in the Apache Software Foundation's incubating repository (as sling is still in the incubator).
So for maven to be able to resolve the plugin, we must add the repository to the pom.
While we're at it, we will also add it both as a plugin and as a regular artifact repository, as we'll be using other parts of sling later on.

Add the following right before the <dependencies> section:

  1: <repositories>
  2: 	<repository>
  3: 		<id>apache.incubating</id>
  4: 		<name>Apache Incubating Repository</name>
  5: 		<url>http://people.apache.org/repo/m2-incubating-repository</url>
  6: 	</repository>
  7: </repositories>
  8: <pluginRepositories>
  9: 	<pluginRepository>
 10: 		<id>apache.incubating.plugins</id>
 11: 		<name>Apache Incubating Plugin Repository</name>
 12: 		<url>http://people.apache.org/repo/m2-incubating-repository
 13: 		</url>
 14: 	</pluginRepository>
 15: </pluginRepositories>

Build and Install

Now, execute maven so:

mvn clean install

 

To verify that the new package is deployed, go to the sling console at http://localhost:7402/system/console/list and click on the "OSGI Test Bundle" to see the details
(this only works in Firefox, not on IE, about others I do not know).

I bumped the version by 0.0.1 for each part of this series, so we're now at 0.0.4.
The version is taken from the pom's <version> element.

snap001 2008-08-29

 

Test

As usual, go to http://localhost:7402/test to see the service say "hello"

Sling OSGi Track pt 3: replacing the Activator with DS

This is the continuation of

In this part, I will show how to declare the SampleService instead of registering it explicitly by an activator

Aims:

  • Show how to declare a service component

Ingredients:

Files:

Outline:

  • Add the scr plugin to the pom
  • Remove the activator
  • Add scr tags
  • Build, Install, Test

Execution:

Add the scr plugin to the pom

Add the following snippet to the build plugins:

  1:  <plugin>
  2:      <groupId>org.apache.felix</groupId>
  3:      <artifactId>maven-scr-plugin</artifactId>
  4:      <version>1.0.7</version>
  5:      <executions>
  6:          <execution>
  7:              <id>generate-scr-scrdescriptor</id>
  8:              <goals>
  9:                  <goal>scr</goal>
 10:              </goals>
 11:          </execution>
 12:      </executions>
 13:  </plugin> 
Remove the activator

As we no longer will use explicit activation, we remove the Activator from the sources and remove the following line from the pom:

<Bundle-Activator>mh.osgitest.Activator</Bundle-Activator>
Add scr tags

Now, we add the scr tags to the implementing class.

Line (4) declares the class as a component. This will provide a wrapped ManagedService Component in the OSGi container (I'll come to ManageServices later)

Line (5) declares the service we are offering. Actually, the interface attribute is superflous, as by default, all implemented Interfaces are used.

  1: package mh.osgitest;
  2:
  3: /**
  4:  * @scr.component
  5:  * @scr.service interface="SampleService"
  6:  */
  7: public class SampleServiceImpl implements SampleService {
  8:  public String sayHello() {
  9:   return "hello";
 10:  }
 11: }
Build, Install, Test

First, mvn clean package

To install the bundle, go to the system console at http://localhost:7402/system/console/list.

Then, call the URL http://localhost:7402/test .

For the detail of these two steps, have a look at the first post in this series: /2008/08/basic-osgi-service-for-sling.html

Thursday, August 28, 2008

Sling OSGi Track pt 2: using Felix' bundle plugin for manifest entries

This is the continuation of  Sling OSGi Track pt 1: hand-rolled service bundle.

In this part, I will remove the manually created MANIFEST.MF, and have it created by the Maven2 felix-bundle-plugin.

Aims:

  • define OSGi-specific manifest entries in pom.xml and let Maven create the manifest

Ingredients:

Files:

Outline:

  • enable and configure the plugin in pom.xml
  • change the packaging style in pom.xml
  • stop merging our own manifest into the created jar and remove manifest file

Execution:

enable and configure the plugin in pom.xml

The plugin configuration is done in lines 20-35.
(27): Export-Package creates and Export-Package manifest entry with the same content
(28): same for Import-Package
(29): the symbolic name is taken from the pom's articactId
(30): the bundle name is taken from the pom's project name
(32): Bundle-Activator -- the main class

change the packaging style in pom.xml

We need to change the packaging style to "bundle" (defaults to "jar") for the plugin to do its work.
This is done in line 8.

  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.2</version>
  8: 	<packaging>bundle</packaging>
  9: 	<description />
 10: 	<build>
 11: 		<plugins>
 12: 			<plugin>
 13: 				<groupId>org.apache.maven.plugins</groupId>
 14: 				<artifactId>maven-compiler-plugin</artifactId>
 15: 				<configuration>
 16: 					<source>1.5</source>
 17: 					<target>1.5</target>
 18: 				</configuration>
 19: 			</plugin>
 20: 			<plugin>
 21: 				<groupId>org.apache.felix</groupId>
 22: 				<artifactId>maven-bundle-plugin</artifactId>
 23: 				<version>1.4.3</version>
 24: 				<extensions>true</extensions>
 25: 				<configuration>
 26: 					<instructions>
 27: 						<Export-Package>mh.osgitest</Export-Package>
 28: 						<Import-Package>org.osgi.framework;version="1.3.0"</Import-Package>
 29: 						<Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
 30: 						<Bundle-Name>${pom.name}</Bundle-Name>
 31: 						<Bundle-Vendor>Moritz Havelock</Bundle-Vendor>
 32: 						<Bundle-Activator>mh.osgitest.Activator</Bundle-Activator>
 33: 						<Built-By>Moritz Havelock</Built-By>
 34: 					</instructions>
 35: 				</configuration>
 36: 			</plugin>
 37: 		</plugins>
 38: 	</build>
 39: 	<dependencies>
 40: 		<dependency>
 41: 			<groupId>org.apache.felix</groupId>
 42: 			<artifactId>org.osgi.core</artifactId>
 43: 			<version>1.0.1</version>
 44: 		</dependency>
 45: 	</dependencies>
 46: </project>

stop merging our own manifest into the created jar and remove manifest file

We can now remove the file src/main/resources/META-INF/MANIFEST.MF, as this will be auto-generated.
Also, we can remove the following section from the pom.

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<version>2.2</version>
				<configuration>
					<archive>
						<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
					</archive>
				</configuration>
			</plugin>
 
Build

Do an "mvn clean package".

Now, open the created jar file ( target/mh.studies.sling.osgitest-0.0.2.jar ), and have a look at the created META-INF/MANIFEST.MF:
as you can see, all the lines we previously created manually are there, looking much the same.
There are slight differences in (7) -- the used packages are declared, and (3), (2), (11) and (15) are new.

  1: Manifest-Version: 1.0
  2: Built-By: Moritz Havelock
  3: Created-By: Apache Maven Bundle Plugin
  4: Bundle-Activator: mh.osgitest.Activator
  5: Import-Package: org.osgi.framework;version="1.3.0"
  6: Bnd-LastModified: 1219937878156
  7: Export-Package: mh.osgitest;uses:="org.osgi.framework"
  8: Bundle-Version: 0.0.2
  9: Bundle-Name: OSGI Test Bundle
 10: Bundle-ClassPath: .
 11: Build-Jdk: 1.5.0_16
 12: Bundle-ManifestVersion: 2
 13: Bundle-Vendor: Moritz Havelock
 14: Bundle-SymbolicName: mh.studies.sling.osgitest
 15: Tool: Bnd-0.0.255

 

Install / Test Client

To install the bundle, go to the system console at http://localhost:7402/system/console/list.

Then, call the URL http://localhost:7402/test .

For the detail of these two steps, have a look at the previous post: /2008/08/basic-osgi-service-for-sling.html

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