Simple database connection in OSGi bundle

This short tutorial follows the topic of my previous post which concerned creation of OSGi bundles. This time we are going to create a simple OSGi bundle able to connect to a database (in our case it would be MySQL) using JDBC. However, the way it is accomplished here should not be considered as the right approach, because I do not think that anyone would use BundleActivator for anything but initialization of the bundle. So, please consider this tutorial only as a sample showing how BundleActivator works.

Project POM

The first steps (project creation and setup etc.) are identical as in the previous case. The project will be created using the following Maven command.

mvn -B archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.0 \
-DgroupId=com.lukaszbaran.simpleosgi.db \
-DartifactId=osgi-simple-db -Dversion=1.0

However, the POM file is quite different than previously because we are not using Spring Dynamic Modules (to show that it is not necessary). So, again, just replace the generated POM with this code:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.lukaszbaran.simpleosgi.db</groupId>
	<artifactId>osgi-simple-db</artifactId>
	<packaging>bundle</packaging>
	<version>1.0</version>
	<name>osgi-simple-db</name>
	<url>http://maven.apache.org</url>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.felix</groupId>
				<artifactId>maven-bundle-plugin</artifactId>
				<extensions>true</extensions>
				<version>1.4.0</version>
				<configuration>
					<instructions>
						<manifestLocation>META-INF</manifestLocation>
						<_include>-osgi.bnd</_include>
					</instructions>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.4.2</version>
				<configuration>
					<skipTests>true</skipTests>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.felix</groupId>
			<artifactId>org.osgi.core</artifactId>
			<version>1.0.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.6</version>
		</dependency>
	</dependencies>
</project>

Code

Before we go further, let us assume that we have got the simplest MySQL database possible. Let’s assume that the db name will be testdb. It would contain only one table whose DDL definition looks as follows:

CREATE TABLE IF NOT EXISTS `names` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;

The table may filled with the following data (of course, it really does not matter):

Sample data

It is time to create the actual code of our bundle. We need only two classes: com.lukaszbaran.simpleosgi.db.Application and com.lukaszbaran.simpleosgi.db.Activator. As it can be read in OSGi specification, Activator class is responsible for bundle initialization and destruction. In our case it is responsible for invoking our database code, which is located in Application class. Of course, both these classes are as simple as possible. Note: Remember about proper MySQL settings in Application.java (which are: dbUrl, dbUser, dbPassword).

package com.lukaszbaran.simpleosgi.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.mysql.jdbc.Driver;

public class Application {

	private static final String dbUrl = "jdbc:mysql://localhost:3306/testdb";
	private static final String dbUser = "youruser";
	private static final String dbPassword = "yourpassword";

	public Application() {
	}

	public void doStuff() {
		Statement stmt = null;
		String driverName = Driver.class.getName();
		Connection con = null;
		try {
			Class.forName(driverName);
			con = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
			stmt = con.createStatement();

			ResultSet rs = stmt.executeQuery("SELECT * FROM names");
			while (rs.next()) {
				int id = rs.getInt("id");
				String name = rs.getString("name");
				System.out.println("\tid= " + id + "\tname = " + name);
			}
			con.close();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
package com.lukaszbaran.simpleosgi.db;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator {

	@Override
	public void start(BundleContext arg0) throws Exception {
		Application app = new Application();
		app.doStuff();
	}

	@Override
	public void stop(BundleContext arg0) throws Exception {
	}
}

The most important part…

This time osgi.bnd file is a little bit sophisticated and, in fact, the most important part of the bundle creation process:

Import-Package: org.osgi.framework, javax.*, org.w3c.dom, org.xml.*, org.apache.commons.logging, org.apache.log4j, !com.mchange.v2.c3p0, !org.jboss.resource.adapter.jdbc, !org.jboss.resource.adapter.jdbc.vendor 

Embed-Dependency: *

Embed-Transitive: true

Private-Package: *

Bundle-Activator: com.lukaszbaran.simpleosgi.db.Activator

Please notice that in the last line we explicitly specify which class will be our BundleActivator. That is the most important thing we are learning in this tutorial. Traditionally, we compile the project with mvn clean package command and copy osgi-simple-db-1.0.jar to deploy directory of Fuse ESB. Immediately after that, we should see our output in the ServiceMix console:

id= 1     name = Smith
id= 2     name = Ford
id= 3     name = Andrews

Web service in OSGi bundle

In this short tutorial we will create OSGi bundle that will expose web service using CXF library. Like it or not, but the project will be created with usage of Maven utility. Also, this example will be using Spring Dynamic Modules.

Project

Let us start with creating an empty project. We will do it using archetype:generate:

mvn -B archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.0 \
-DgroupId=com.lukaszbaran.simpleosgi.ws \
-DartifactId=osgi-simple-ws -Dversion=1.0

After execution of this command, Maven should generate project structure. Delete the classes AppMain and AppTest. To make the project simpler to edit, generate Eclipse project files:

mvn eclipse:eclipse

Code & configuration

The next step is to create the interface and its implementation (don’t forget about packages as well):

 // ICalculator.java
 package com.lukaszbaran.simpleosgi.ws;
 import javax.jws.WebService;
 @WebService
 public interface ICalculator {
    int add(int a, int b);
    int sub(int a, int b);
 }

Service implementation (CalculatorImpl.java) is created in com.lukaszbaran.simpleosgi.ws.impl package:

// CalculatorImpl.java
package com.lukaszbaran.simpleosgi.ws.impl;
public class CalculatorImpl implements ICalculator {
	@Override
	public int add(int a, int b) {
		return a + b;
	}
	@Override
	public int sub(int a, int b) {
		return a - b;
	}
}

Since the project is going to use Spring Dynamic Modules, it is necessary to create beans.xml file in src / main / resources / META-INF / spring / beans.xml path. The file should look like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:jaxws="http://cxf.apache.org/jaxws"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
	<import resource="classpath:META-INF/cxf/cxf.xml"/>
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
	<import resource="classpath:META-INF/cxf/cxf-extension-http.xml"/>
	<import resource="classpath:META-INF/cxf/osgi/cxf-extension-osgi.xml"/>
 <jaxws:endpoint
  id="calculator"
  implementor="com.lukaszbaran.simpleosgi.ws.impl.CalculatorImpl"
  address="/calculator"/>
</beans>

This file defines the address of our end-point and and points the class which implements service interface.

POM

The next step is to create pom.xml file that will be used to build our project (of course, if you were doing this tutorial from the beginning, the only thing you need to do is to copy build section from the following XML into your POM).

<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.lukaszbaran.simpleosgi.ws</groupId>
	<artifactId>osgi-simple-ws</artifactId>
	<packaging>bundle</packaging>
	<version>1.0</version>
	<name>osgi-simple-ws</name>
	<url>http://maven.apache.org</url>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.felix</groupId>
				<artifactId>maven-bundle-plugin</artifactId>
				<extensions>true</extensions>
				<version>1.4.0</version>
				<configuration>
					<instructions>
						<manifestLocation>META-INF</manifestLocation>
						<_include>-osgi.bnd</_include>
					</instructions>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
</project>

As you can see, in the code above we configured maven-bundle-plugin, so that it would use configuration from osgi.bnd file.  It should be created in the same directory as pom.xml file:

Import-Package: javax.jws, javax.wsdl, META-INF.cxf, META-INF.cxf.osgi, org.apache.cxf.bus, org.apache.cxf.bus.spring, org.apache.cxf.bus.resource, org.apache.cxf.configuration.spring, org.apache.cxf.resource, org.apache.servicemix.cxf.transport.http_osgi, org.springframework.beans.factory.config 

Private-Package: com.lukaszbaran.simpleosgi.ws.*

Require-Bundle: org.apache.cxf.cxf-bundle

Compilation & installation

The project should be compiled by executing:

mvn clean package

If everything has been done correctly, the bundle should be now in the target directory. To make our bundle running in OSGi environment (in our case it would be Fuse ESB) we should take care of installing cxf-osgi feature (feature is simply a pack of bundles). In Fuse ESB we do it using the following command:

features install cxf-osgi

Note: if you do not do this you may get some strange exceptions like this one:

org.osgi.framework.BundleException:
 Unresolved constraint in bundle 154:package;
 (package=META-INF.cxf.osgi)

Now we can install our bundle in the container (e.g. by copying to the container’s deploy directory). Service may be accessed by opening URL: http://localhost:8080/cxf/calculator?wsdl (assuming the default configuration).