Showing posts with label OSGi. Show all posts
Showing posts with label OSGi. Show all posts

January 22, 2009

Configuring Apache Felix to host web applications

I have been doing lot of work on OSGi technologies lately. Recently we have seen many application server move from their core server technologies to OSGi based ones. In this article we will see how to configure Apache Felix to host simple web applications built using JSP and servlet technology.

We have less stuff to do. Thanks to the community, all you need to do is download the necessary bundles, make your WARs an OSGi bundle and finally load all the bundles on an OSGi runtime.

OPS4J community provides us the necessary bundles that help us host WAR files. We will use OPS4J three projects: Pax Web, Pax Web Extender and Pax logging.

Pax web is a OSGi R4 HTTP Service implementation using Jetty 6.

Pax Web Extender is a project that extends and adds more functionality to Pax web. The extender project has three modules: Pax Web Extender – War, Pax Web Extender – Whiteboard and Pax URL. We will be using the Pax Web Extender – War bundle. The bundle that makes possible to deploy WAR files into OSGi runtime.

And finally, Pax logging provides an OSGi logging service and API. It is built on top of log4j and supports Jakarta Commons Logging API, Log4J Logger API, JDK Logging, Avalon Logger API, Knopflerfish Log and Tomcat Juli in both your own code and in third party libraries.

You can download these from OPS4J site.

Build your web application on any IDE or compile it into a war using Ant. But before deployment we need to ensure that the archive is a valid bundle. To make the web application a bundle we need to have the following manifest headers in META-INF/MANIFEST.MF.

Bundle-ManifestVersion: 2 -- This header defines that the bundle follows R4 specification.
Bundle-SymbolicName -- This header specifies a unique, non-localizable name for the bundle.
Bundle-ClassPath –- This header specifies list of all JAR and resources in your bundle. Each entry is separated by comma and the root directory is represented by period. Example: Bundle-ClassPath: .,WEB-INF/classes,lib/commons-logging.jar,lib/spring.jar
Import-Package -- This header defines the list of packages that your application depends on. All necessary J2EE packages would come here.

Additionally, you can have some optional headers like
Webapp-Context -- The header defines the context path. Please note that this is not a standard OSGi header.

You may also include other standard OSGi headers for adding information to the bundle. Once you have the WAR file with modified manifest information we are ready to deploy our application. Deployment is simple the installation of the bundle.

You can install the bundle using the install command from the Felix shell or modify the conf/config.properties. Once installed, check if the bundle’s state is active and then access your web application using your browser.

Caution: Please note that, if you have created your WAR using Netbeans you will have sun-web.xml. More than one configuration file causes resource registration failure in Pax Web Extender. You will have to remove this file.

For now we have only used one of the modules from Pax Web Extender. You may try other modules as they also provide interesting functionalities for a developer.

January 15, 2009

Building a "Hello World" service using iPOJO

iPOJO stands for injected POJO. It’s a component model from Apache on top of OSGi. It is very flexible, extensible and easy to adapt. It removed the overhead of developer handling services in OSGi. Let’s have a look how to build a simple service using iPOJO and consume it.

OSGi is about modularizing your application. In our demo, we will have three projects (or three bundles) that will be deployed on Apache Felix. I suggest you download the following tools and ligraries before we start out with our project.
1.Apache Felix: http://felix.apache.org/
2.iPOJO library: http://felix.apache.org/
3.Ant: http://ant.apache.org/
4.Bnd tool from aQute: http://www.aqute.biz/Code/Bnd

The Problem Statement

Our problem is going to be very simple. Our service is a simple OSGi service that will display the string “Hello World”.

Getting Started

Like any OSGi service, our service is represented as an interface:
package hello.service;
public interface HelloService {
public String sayHello();
}
This will be our first project or first bundle. The bundle will have just the interface. Please note that you will have to export hello.service package when building the bundle. To make this task easy, use the bnd tool to create the jar. I have used Ant script to compile and package the projects. Once bundle is ready, you will use it as a dependency library for compiling other projects.

Implementing our service

The next step is to implement our service. We will create a new project with previous projects jar file as a dependency. The service implementation is also POJO and there is no mention of OSGi service in the code. Let’s have a look at our implementation:
package hello.component;
import hello.service.HelloService;
public class HelloComponent implements HelloService {
String message = "Hello World";
public String sayHello() {
return message;
}
}
Now we define that we have a iPOJO component. This is done through a xml that is placed along with the project. The xml defines that, we have a component of the class hello.component.HelloComponent. The example below is a very simple one, you can have callbacks, properties set etc in this xml using different xml elements.
<ipojo>
<component classname="hello.component.HelloComponent">
<provides/>
</component>
<instance component="hello.component.HelloComponent"/>
</ipojo>
We will compile this project into another bundle that will be deployed in the runtime.

Using our Service

This is our final project. This project will be consuming the service we created above. The client can be a POJO or a Activator class. Like the service implementation code, we do not code for a service. Instead we go about and code as if the implementation is available to us. iPOJO framework would take care of the rest. Here is our "hello world" client:
package hello.client;
import hello.service.HelloService;
public class HelloClient {

private HelloService m_hello;

public HelloClient() {
super();
System.out.println("Hello Client constructor...");
}

public void start() {
System.out.println("Starting client...");
System.out.println("Service: " + m_hello.sayHello());
}

public void stop() {
System.out.println("Stoping client...");
}
}
I have some sys outs to see how our client work. Just like the service project, we have a xml that will define what is the required service, callback functions etc. Have a look at the xml:
<ipojo>
<component classname="hello.client.HelloClient">
<requires field="m_hello"/>
<callback transition="validate" method="start"/>
<callback transition="invalidate" method="stop"/>
</component>
<instance component="hello.client.HelloClient"/>
</ipojo>
The xml specifies that HelloClient requires m_hello to execute. m_hello is a instance of our service. So as long as the service is not available, the HelloClient component do not get executed. The callback xml elements specify which methods to execute when the state of the component changes.

Once compiling and packaging of this project is done, we are ready to deploy our example into a runtime and see it working. If you have Felix and iPOJO framework downloaded. Let’s configure Felix to load our bundles when it’s started.

Felix configurations are placed in config.properties under conf folder.You will have to modify the entires for felix.auto.start.1 variable. Here is how it looked like after I modified:
felix.auto.start.1= \
file:bundle/org.apache.felix.shell-1.0.1.jar \
file:bundle/org.apache.felix.shell.tui-1.0.1.jar \
file:bundle/org.apache.felix.bundlerepository-1.0.3.jar \
file:bundle/org.apache.felix.ipojo-1.0.0.jar \
file:bundle/hello.service.jar \
file:bundle/hello.component.jar \
file:bundle/hello.client.jar
I have put all my jars in felix/bundle folder. You may place them in different location and specify the path.

We are ready now. Run your felix runtime to see the results! You may download the complete project and experiment with iPOJO. Good luck :)

November 30, 2008

Building a simple OSGi Service

I have been experimenting with this technology and the main inspiration came from SpringSource's dm Server. Like other OSGi evangelist,I am beginning to see OSGi technology as technology that will transform Java development. I would like it to be more on the enterprise side. In this session, we will see how to build a simple service and consume it.

I started of my OSGi quest with Equinox and Eclipse IDE. But for the tutorial that we have today, we do not need Eclipse as it's a simple application (bundle). You may also use other OSGi runtime like Apache Felix or Knopflerfish. Knopflerfish even gives you are good GUI to work with. I will not be explaining fundamentals of OSGi technology. You may refer the technology overview, technical whitepaper and business whitepaper for more information.

What's OSGi service?
In very general terms, a service is a repeatable task. When it comes to business, any repeatable task in your business process is a service. Similarly in a application, you can have generic tasks (even specific tasks) that are repeatedly used can be represented as service. Representing and using these tasks as services is what SOA is all about! But that' at an enterprise level. When it comes to OSGi services, it is the same concept but applied at JVM level.

In OSGi, a service is a plain java object which is published to a registry. A consumer can consume the registered service through lookup. A service a be registered and unregistered at any point of time. Service is built using interface-based programming model. To implement or build a service you basically provide implementation to a interface. To consume, you only need the interface for the lookup and there is no need to know about the implementation. The service registry is the "middle man" who help producers and consumers to get in touch with each other.

Building HelloWorld service
The first step would be to create our interface or "front end" of our service. For our service, we will have a simple interface named IHelloService:
package org.tp.service.helloservice;

public interface IHelloService {
public String sayHello();
}
And here is our service implementation.
package org.tp.service.helloservice;

public class HelloService implements IHelloService {
public String sayHello() {
return "Hello World";
}
}
That's it! Our service is ready for use. But, we need to inform consumers that the service is ready to serve. For this, we will have to register our service with the OSGi service registry.

OSGi framework provides us with standard APIs to register and unregister service with the registry. We will use the registerService method to register as shown below:
serviceRegistration = context.registerService(IHelloService.class.getName(),helloService,null);
I am sure for beginners this is not enough. Let's explain the stuff little further.To register our new service, we will build a simple bundle that will call registerService method.
package org.tp.service.helloservice;

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

public class Activator implements BundleActivator {

private ServiceRegistration serviceRegistration;
private IHelloService helloService;

public void start(BundleContext context) throws Exception {
System.out.println("Starting HelloService Bundle..");
helloService = new HelloService();
serviceRegistration = context.registerService(IHelloService.class.getName(),helloService,null);

}

public void stop(BundleContext context) throws Exception {
serviceRegistration.unregister();
}

}
Our Activator class implements BundleActivator. Basically, its a simple OSGi bundle with start and stop methods. We will register our service with the bundle starts up and unregister when the bundle is uninstalled from the framework.

Now lets have a closer look at start method. We create a instance of our service and then use registerService method. The first argument is service name which is obtained using InterfaceName.class.getName(). Its a best practice to use this method instead of specifying the name as string (org.tp.service.helloservice.IHelloService). The second argument is the instance of the service itself. And the final argument is Map wherein developers can pass additional properties to the service.

To unregister the service, we simple call unregister method when we stop the bundle. So now we have a running service on our OSGi runtime. Lets see how to consume it.

Consuming a service
To consume a service, we first create serviceReference object form the BundleContext. This can be achieved by calling getServiceReference method. The method takes the class name as a argument. Once you have the serviceReference object, we will use getService method to finally get the service. We will have to typecast the object returned by getService method before using it.
helloServiceRef = context.getServiceReference(IHelloService.class.getName());
IHelloService serviceObjectHelloService = (IHelloService)context.getService(helloServiceRef);
System.out.println("Service says: " + serviceObjectHelloService.sayHello());
Implementing the service and consumer is the same package is easy. Because, the interface is available. When you have your service and consumer bundle separate, there are some important points to note. OSGi provides the capability of specifying the packages they can be exported or imported. With this facility you can expose your service interface and hide its implementation from the public. The configuration details are specified in the MANIFEST file. Have a look at our HelloService's MANIFEST file:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: HelloService Plug-in
Bundle-SymbolicName: HelloService
Bundle-Version: 1.0.0
Bundle-Activator: org.tp.service.helloservice.Activator
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: org.osgi.framework;version="1.3.0"
Export-Package: org.tp.service.helloservice;uses:="org.osgi.framework"
Notice that we have exported org.tp.service.helloservice package. Similarly, we import this package in our consuming bundle.

You may download the complete code of this tutorial. I have two eclipse projects, HelloService – implementation of the service and HelloBundle – will consume the service. And to add some notes; The code used for consuming the service is not the best way. I have made the code very simple and easy to understand without involving Exceptions handling,Null pointer checks and ServiceListeners. We will have a look at ServiceListeners next.

November 06, 2008

Sun Introduces OSGi based Server: Glassfish V3

Sun Microsystems announced the availability and support of the their latest application server: GlassFish version 3 Prelude. The application server is a lightweight and based on modular architecture. The new server is also a preview to the next version of java enterprise edition (JEE 6). Let's have look at Gfv3's features.

GlassFish is one of the leading open source application server. Sun claim to have more than 14 million downloads of the server. But I wonder how many are used in production environment and not by students and developers (I have a regirstered version of Gfv2 on my laptop)? The new version of server was redegined from top to bottom to run on the popular modular runtime called OSGi runtime. Glassfish makes use of Apache Felix, an open source OSGi runtime from Apache. Sun claims that, the application server can also run on Eclipse's Equinox runtime.

The server brings in lots of changes in how an application sever works. The server startup time is drastically reduced compared to the pervious version. This was acheived by the way how classes are loaded in the server. At startup a full fledged application server do not start, instead only the necessary modules (containers) get loaded.Containers do not get loaded unless they have a component to execute. For example, EJB container do not start untill I have a EJB depoyed.

The server comes with a full web container that can host servlets 2.5, JSP and JSF. JSF 2.0 is provided as preview. Developers can also have a first look at EJB 3.1. They can also make use of the JPA for persistence. Sun introduces the concept of a update center from which you can download other modules like web service stack or Jersey . The server also introduces containers that support native jRuby/Rails, Groovy/Grails.

The major advantage for a development team from GlassFish is that it provides the ability to maintain the sessions active even during deployment. This feature helps both developers and testers to test the code, refine them if need and test it rather than going through the long cycle that we currently go through. So next time you find a bug when testing your code, all you need to do is change your logic, deploy and start testing with the same session. Netbeans 6.5 is said to have good integration with the new server, providing deployment of new code on the server as and when you save the code and its compliation error free! Other advantages includes the availability of easy to use admin and cofiguration tool and server being available for all major platforms.

Now we have SpringSource,IBM and Sun implementing application servers on OSGi technology, are we seeing the tsunami of OSGi support and implementation? Even thought these changes do not provide a visible change to the end users, JEE seems to be adopting OSGi technology at a large scale. I am sure Oracle will come up with an implementation using their (orginally BEA's) mSA technology, which is based on OSGi.