This page last changed on Nov 03, 2005 by jdeolive.

This page summarizes some of the research that has been going on with regard to the Geoserver 2.0 project. Its mosly a summary of various candidate technologies.

Criteria

The following is a summary of the criteria being used to evaluate new technologies to base the next round of geoserver on.

Plug-in Architecture

Most modern frameworks employ a plug-in architecture. This is necessary for the following reasons:

  • It gives developers an easy and defined way to contribute to the project.
  • It gives developers a sense of ownership over the plugins they develop.

Ease of Development

A plug-in framework is good, but an easy-to-use plug-in framework is better. Easy-to-use is a loose term so lets try to be a little bit more specific:

Documentation

Unless an API is well documented, which includes examples/articles of how to use it, no one will use it. Furthermore, the more documentation that exists is the less we have to write.

Tool / IDE Support

Its tedious to when writing a component of some sort to have to hack xml configuration files directly. Having tools to eleviate these sorts of tasks can increase developer productivity and at the same time keep them from going insane.

One of the reasons that eclipse is so successful is that they have an IDE that directly supports their component model.

Strong Programming Model

Many frameworks impose some sort of programming model on the developer. As an example, Eclipse makes use of extension points, and extensions (if these terms mean nothign to you don't worry). What this model does is lay down the ground rules that components should follow when interacting with the framework, and with other components. As the complexity of a system grows, these kind of rules become vital to managing components.

Integration

People are often constrained by the technologies they "have" to use. For instance, most people have the need to be able to run GeoServer on their specific J2EE application server. For this reason the GeoServer technology must be able to integrate with existing technologies, most notibly J2EE.

For this reason the GeoServer framework must be suitably light-weight.

Longevity

There are a mountain of frameworks for doing various things out there. However most of these frameworks are not successful in that they do not withstand the test of time. The last thing we want is to stick our developers with a dying technology. So we need to be careful to choose a technology that will be around in 5 years.

In doing so, we will be able to use an existing and well established developer community in order to nurture and grow our own. The growth of the underlying technology will untimatley dictate the growth of GeoServer 2.0.

Example Application

It will help to have an example application to work with as we examine the different technologies. Since one of the geoserver 2.0 goals is to allow people to quickly develop new services, let us focus there.

The example will be a simple web application which handles GetCapabilities requests for an arbitraty service. The application must be structured in a way which allows new types of services to be plugged in.

Lets start with a simple interface.

/**
 * Generic service interface.
 */
interface Service {
  /**
   * Returns an string which identifies the service.
   */
  String getServiceId();

  /**
   * Writes the capablities of the service to an output stream.
   */
  getCapabilities(OutputStream out);
}

And a couple of implementations:

/**
 * Web Map Service
 */
class WMS implements Service {

  String getServiceId() {
    return "wms";
  }

  getCapabilities(OutputStream out) {
    //write out the capabilities document
    out.write("<WMS_Capabilities...");
  }
}

/**
 * Web Feature Service
 */
class WFS implements Service {

  String getServiceId() {
    return "wfs";
  }

  getCapabilities(OutputStream out) {
    //write out the capabilities document
    out.write("<WFS_Capabilities...");
  }
}

The above classes make up the domain model for the example application.

Candidate Technologies

Now that we have our criteria somewhat nailed down and an example to work with, lets start looking at the candidate technologies.

Geronimo / GBeans

Welcome to Apache Geronimo, the J2EE server project of the Apache Software Foundation. Please help us make this a world class, certified J2EE container!

The aim of the project is to produce a large and healthy community of J2EE developers tasked with the development of an open-source, certified J2EE server that:

  • is licensed under the Apache License
  • passes Sun's TCK for J2EE 1.4
  • reuses the best ASF/BSD licensed code available today, with new ASF code to complete the J2EE stack.

The primary goal of the Geronimo project is to build a fully certified J2EE implementation bringing together many other projects which implement various parts of J2EE. Examples include Jetty, Derby, OpenEJB, and more...

At the core of the project is the Geronimo Kernel and the GBeans architecture. The geronimo kernel is essentially and IoC container. Components that live inside the container are called Gbeans. Lets introduce with an example. The following denotes a plain old java interface Foo, and two implementations of Foo: FooImpl1,FooImpl2.

interface Foo {
   void foo();
}

class FooImpl1 implements Foo {
  void foo() {
    System.out.println("FooImpl1 here.");
  }
}

class FooImpl2 implements Foo {
  void foo() {
    System.out.println("FooImpl2 here.");
  }
}

Nothing earth shattering here. Ok, so what the following code does is fire up the kernel, and load our components into it
by creating GBeans for them.

//create and boot the kernel
Kernel kernel = KernelFactory.newInstance().createKernel("test");
kernel.boot();

//build the bean for foo1
GBeanInfoBuilder builder = new GBeanInfoBuilder(FooImpl1.class);
builder.addInterface(Foo.class);   
builder.addOperation("foo");

GBeanData fooBean1 = new GBeanData(new ObjectName(":name=foo1"),builder.getBeanInfo());

//build the bean for foo2
builder = builder = new GBeanInfoBuilder(FooImpl2.class);
builder.addInterface(Foo.class);   
builder.addOperation("foo");
GBeanData fooBean2 = new GBeanData(new ObjectName(":name=foo2"),builder.getBeanInfo());
   
//load beans into kernel 
kernel.loadGBean(fooBean1);
kernel.loadGBean(fooBean2);

//start their lifecycle
kernel.startGBean(new ObjectName(":name=foo1"));
kernel.startGBean(new ObjectName(":name=foo2"));

Ok so lets look at this code a bit closer.

Kernel kernel = KernelFactory.newInstance().createKernel("test");
kernel.boot();

The first thing it does is creates an instance of the kernel (our container) and fires it up. No real magic here.

GBeanInfoBuilder builder = new GBeanInfoBuilder(FooImpl1.class);
builder.addInterface(Foo.class);   
builder.addOperation("foo");

The next thing that happens is that a GBeanInfoBuilder is created. The role of this class is to build up the metadata for our object, in this case an instance of FooImpl1. Put another way, it is used to build up the things that our component wishes to expose to other components (interfaces, attributes, operations, etc...).

GBeanData fooBean1 = new GBeanData(new ObjectName(":name=foo1"),builder.getBeanInfo());

Next, an instance of GBeanData is created. This is essentially the bean itself. It contains all the metadata from above, plus an unique identifier, which is an instance of ObjectName. This is a construct from the JMX (Java Management Extensions) specification. Among other things, its role is to identify the bean.

kernel.loadGBean(fooBean1);
kernel.loadGBean(fooBean2);

Next, the beans are loaded into the kernel. This only loads the beans, it does not create the underlying components (instances of FooImpl1, and FooImpl2).

kernel.startGBean(new ObjectName(":name=foo1"));
kernel.startGBean(new ObjectName(":name=foo2"));

And lastly, the beans are started. Starting a bean actually creates the underlying component and starts its life-cycle.

Ok so what, that was a lot of work, what is the big deal? Well there are a few things to note about the Geronimo kernel architecture:

  • Creating an instance of the kernel is straight forward, making it easily embeddable.
  • Each component must be described to the kernel. This allows the component full control over what becomes public interface and accessible to other components.
  • Components are lazily-loaded and not instantiated until explicity started, or until another components asks for it.

Next let us investigate how some client code would be able to use our components. Consider the following code:

//obtain a reference to the kernel, somehow ...
Kernel kernel = ...

//query the kernel for implementations of Foo
List foos = kernel.listGBeans(Foo.class);

//for each implementation do some work
for (Iterator itr = foos.iterator(); itr.hasNext();) {
  ObjectName name = (ObjectName)itr.next();
  
  //invoke the foo method
  kernel.invoke(name,"foo");
}

Some more things to note:

  • The ability to perform queries against the kernel gives components dynamic access to each other.
  • The result of a query returns an ObjectName, and not the component itself. This keeps components loosly coupled.
  • Operations are invoked through the kernel. Among other things, this allows components to be proxied.

Evaluation

Plug-in Architecture.

The GBean architecture employs a nice plug-in architecture. The indirection provided by the kernel keeps components nicley isolated from each other while at the same time providing easy access. Being used as the core of a full-blown J2EE server pretty much proves it to be robust. And being integrated with various other projects hints at its flexibilty.

Ease of Development

The Geronimo kernel itself is farily low-level. The provided example is about as simple as it gets and amounted to close to a few dozen lines of code. It is clear that higher-level constructs are needed to make things easier to use. These constructs may already exist, however the project is still very young and hasn't had a 1.0 release yet. Documentation is sparse.

Integration

I dont think much here needs to be said, the geronimo project itself is one big integration of a handful of projects such as OpenEJB, Jetty, Derby, etc... The kernel is sufficiently lightweight enough to embedd in other applications.

Longevity

The project is still young however enough of the major players have shown interest to ensure that the project will make it to the 1.0 release and beyond. How successful it will be after that, well only time will tell.

J2EE

J2EE may be used as the base framework for GeoServer 2.0.
There're several open source J2EE container implementations to choose from, each with its own strengths and weaknesses.

JBoss Application Server

JBoss Application Server is the #1 most widely used Java application server on the market. A J2EE certified platform for developing and deploying enterprise Java applications, Web applications, and Portals, JBoss Application Server provides the full range of J2EE 1.4 features as well as extended enterprise services including clustering, caching, and persistence.

Plug-in Architecture.

To be done...

Ease of Development

To be done...

Integration

The recently released 4.0.3 version of JBossAS is built around the new JBoss Microcontainer that should make it possibile to use the same configuration and plugins, both with standalone apps and inside a J2EE container.

The JBoss Microcontainer provides a lightweight container for managing POJOs, their deployment and configuration.
Project goals include:

  • Make the JBoss Microcontainer available as a standalone project.
  • Embrace JBoss' POJO middleware strategy.
  • Enable JBoss services to be easily deployed in the other containers.
  • Allow the features to be used in more restrictive environments (e.g. Applets, J2ME, etc.).
  • Provide POJO configuration management, support for dependencies, and support for clustering.

Longevity

There're no doubt about this point for JBoss...

Document generated by Confluence on May 14, 2014 23:00