Getting started with Cooee under Eclipse or Equinox

Setting up an Environment

Ensure you have a working copy of Eclipse 3.3 (3.2 will also work, however it will require more effort, which is not detailed here). If you haven't got one, download one! Upon downloading this, there are two ways you can get a Cooee Development Environment up and running.

Running Cooee from the plugins

Cooee only has a very small amount of dependencies, and this holds true for an OSGI environment. Infact there are only three packages imports that Cooee will need for running inside your OSGI environment. These are:

  • javax.servlet
  • javax.servlet.http
  • org.osgi.framework

Under Eclipse 3.3, all of these will be available in the standard Eclipse Plugins directory. This means that you need only take the Cooee-1.1.jar and also place it in your Eclipse plugins directory to make Cooee available.

Running Cooee from the source

Cooee will also function within Eclipse directly from the source code. There are two ways to set up your environment under this method:

  1. Checkout the code from http://svn.karora.org/repos/cooee/trunk/core
  2. Use the team project set (which also includes the demos, and required dependencies if using Eclipse 3.2) The TPS (.psf) can be found here: Running Cooee Embedded in Eclipse

Under Eclipse 3.3, all of the dependencies needed for Cooee will be provided by the Eclipse/Equinox platform.

Building a Hello World application

Before building your application, make sure you have created a new Java project, or if you're really keen, a new PDE project (Equinox Plugin) within Eclipse.

How to define a MANIFEST.MF, to make your project OSGI compatibile, will be detailed later in this tutorial.

Defining Required Framework Classes

To build a Cooee application, there are two classes that you must extend.

  • "WebContainerServlet", which provides the information to the Web Container as to what Cooee "Application Instance" you wish to use.
  • "ApplicationInstance", which is your actual Cooee application.

Providing a WebContainerServlet implementation

The implementation of the WebContainerServlet is very straight forward. Here, we essentially just want to tell the framework what implementation of ApplicationInstance we wish to use.

Below is an example from the Cooee Demo:

package org.karora.cooee.testapp;

import org.karora.cooee.app.ApplicationInstance;
import org.karora.cooee.webcontainer.WebContainerServlet;

/**
 * Interactive Test Application <code>WebContainerServlet</code> implementation.
 */
public class InteractiveServlet extends WebContainerServlet {

    /**
     * @see org.karora.cooee.webcontainer.WebContainerServlet#newApplicationInstance()
     */
    public ApplicationInstance newApplicationInstance() {
        return new InteractiveApp();
    }

}

Providing an ApplicationInstance implementation

The skeleton of an Application Instance will look something like the following:

package org.karora.cooee.testapp;

import org.karora.cooee.app.ApplicationInstance;
import org.karora.cooee.app.Window;

public class HelloWorldApplication extends ApplicationInstance
{

    public Window init() {
	// TODO Auto-generated method stub
	return null;
    }

}

Within the init() method, we must return a Window object to the framework upon which our application will sit. A simple implementation of the init() method will create a Window object, and then place a Cooee Pane of some form upon it. An example of such is below:

public Window init()
  {
      mainWindow = new Window();
      mainWindow.setTitle("Karora Cooee Test Application");
      mainWindow.setContent(new HelloWorldContentPane());
      return mainWindow;
  }

In this example, we set the content of the MainWindow to be a "HelloWorldContentPane". The only object type that is accepted as the content for the Window is a ContentPane, upon which all other components will need to be placed.

Below is an example of a very simple "Hello World" Content Pane:

package org.karora.cooee.testapp;

import org.karora.cooee.app.ContentPane;

public class HelloWorldContentPane extends ContentPane
{
   public HelloWorldContentPane()
   {
      Column c = new Column();
      add(c);
      Label helloLabel = new Label("Hello World");
      c.add(helloLabel);
   }
}

Getting it all happening in OSGI

Defining an OSGI activator

For a Cooee application to function under OSGI or within the Eclipse environment, you will need to define an OSGI Activator. This activator provides a mechanism to register your Cooee application upon start up. Below is an example as to how this activator may look:

package org.karora.cooee.testapp.osgi;

import org.karora.cooee.testapp.InteractiveServlet;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpService;
import org.osgi.util.tracker.ServiceTracker;

public class Activator implements BundleActivator{

       private ServiceTracker httpServiceTracker;

       private static BundleContext bundleContext;

	    public void start(BundleContext context) throws Exception
	    {
	    	Activator.bundleContext = context;
	        registerServletService();
	    }

	    public void stop(BundleContext context) throws Exception
	    {
	        httpServiceTracker.close();
	        httpServiceTracker = null;
	    }

	    private class HttpServiceTracker extends ServiceTracker
	    {

	        public HttpServiceTracker(BundleContext context)
	        {
	            super(context, HttpService.class.getName(), null);
	        }

	        public Object addingService(ServiceReference reference)
	        {
	            HttpService httpService = (HttpService) context
	                    .getService(reference);
	            try
	            {
	            	InteractiveServlet interactiveServlet = new InteractiveServlet();
	            	httpService.registerServlet("/app", interactiveServlet, null, null);

	            }
	            catch (Exception e)
	            {
	                e.printStackTrace(System.err);
	            }
	            return httpService;
	        }

	        public void removedService(ServiceReference reference, Object service)
	        {
	            HttpService httpService = (HttpService) service;
	            httpService.unregister("/app"); //$NON-NLS-1$
	            super.removedService(reference, service);
	        }
	    }

	    public static BundleContext getContext()
	    {
	        return bundleContext;
	    }

	    private void registerServletService()
	    {
	        httpServiceTracker = new HttpServiceTracker(bundleContext);
	        httpServiceTracker.open();
	    }

}

There are two key parts to this activator.  Firstly, the activator must provide a mechanism for registering servlets with the OSGI environment.  This is done through the following piece of code:

private void registerServletService()
{
	httpServiceTracker = new HttpServiceTracker(bundleContext);
	httpServiceTracker.open();
}

When called by the activator, this provides us with a reference to the HttpServiceTracker, which will allow us to register a servlet in the OSGI environment. This registration occurs via the following line:

InteractiveServlet interactiveServlet = new InteractiveServlet();
httpService.registerServlet("/app", interactiveServlet, null, null);

 

In the above, we create a new instance of the servlet for the Cooee application.  This servlet is then registered via the Http Service.

Defining your MANIFEST.MF file

There are two ways of defining a manifest for an OSGI project. One is via the user interface provided by Eclipse, the other, by hand. For the moment, we'll look at defining this by hand.

For your new application to work under OSGI and inside Eclipse, you need to tell OSGI via the Manifest file, the name of your plugin, the name of your Activator, any other plugins that your application is dependent on (namely Cooee), and any non rt.jar (ie: outside of java., javax.) dependencies. This file should be located in the /META-INF folder within your project and any generated JAR files.

Below is an example of how this should look.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Cooee Hello World
Bundle-SymbolicName: org.karora.cooee.demo
Bundle-Version: 1.1
Bundle-Vendor: Karora
Require-Bundle: org.karora.cooee
Bundle-Activator: org.karora.cooee.testapp.osgi.Activator
Import-Package: javax.servlet;version="2.3.0",
 javax.servlet.http;version="2.3.0",
 org.osgi.framework;version="1.3.0",
 org.osgi.service.http;version="1.2.0",
 org.osgi.util.tracker;version="1.3.2"
Export-Package: org.karora.cooee.testapp

Ensure you have in your Manifest:

  • Require-Bundle: org.karora.cooee
    This ensures that your application can find the Cooee classes
  • Bundle-Activator: <packageName>.Activator
    Where <packageName> is the name of the package where your Activator is located, this is required to tell OSGI where your plugin activator is located
  • Import-Package: javax.servlet;version="2.3.0", javax.servlet.http;version="2.3.0", org.osgi.framework;version="1.3.0", org.osgi.service.http;version="1.2.0", org.osgi.util.tracker;version="1.3.2"
    This tells OSGI which classes you wish to explicitly import from other OSGI bundles. If you hit ClassNotFound exceptions, its because you haven't specified your import here
  • Export-Package: org.karora.cooee.testapp
    This tells the OSGI world what package you want other bundles, namely Cooee, to be able to see.
    "Manifest files and version numbers"
    Strictly speaking, version numbers like so:
    org.osgi.service.http;version="1.2.0"

    Are not required in the OSGI environment and may be safely left out of your manifest file. However as OSGI is a dynamic environment, in which there may be several different versions of the same library, sometimes it may be necessary to specify which version of a given library you require.

Echo, Spring Application Platform (S2AP)

- While many examples referring to Cooee can also be directly used with NextApp's Echo library, at the time of writing Echo 2 RC4 and Echo 3 do not contain OSGI support. Consequently, all OSGI aspects of this tutorial will not work.

- Spring Application Platform, (S2AP) at time of writing does not support the use of the OSGI Http service by bundles - consequently, this example will not work. It is possible however to modify the headers used in the MANIFEST.MF to allow for Cooee applications to be registered - however that is out of scope for this example

Labels