RAP/RWT-OSGi Integration II

In my last post about the new RWT-OSGi integration bundle of RAP 1.5 I have promised to provide a little example of how to use RWT in combination with the ConfigurationAdmin service of OSGi. In this post I will keep that promise and show how to register RWT applications arbitrarily at different http service instances. To do so I use the configuration admin service and the CommandProvider service of Equinox. The sources of the example can be found at https://github.com/fappel/RWT_CONFIG_ADMIN_EXAMPLE 1.

The Example

I start with a short walk through of the example’s main functionality. Some of the development details behind the scenes are covered in the next section. The example project contained in the source repository mentioned above includes a launch configuration called RWT-OSGi-ConfigurationAdmin. After launching it we can type “help” 2 into the OSGi console window of the newly created process. This displays a list of the commands available to control the system.

Those who are familiar with the equinox console will detect a new block:

---Configuration of ApplicationLauncher---
	startHttpService <port>
	stopHttpService <port>
	deployApplication <configurator name>|<port>|<contextName(optional)>
	undeployApplication <configurator name>|<port>|<contextName(optional)>

With the first two commands we can start and stop an instance of HttpService. The service will be bound to the port specified by the command parameter:

Start of Http Service

The screenshot shows the print out after starting two http service instances, one at port 10010 and one at 10020. Pointing your browser to the URL http://localhost:10010/ or http://localhost:10020/ respectively shows that the services are alive but return an HTTP 404. This is quite ok since we did not register any resources yet to be found. We will change this by typing:

Deploy Application

Using the URLs http://localhost:10010/helloworld or http://localhost:10020/datepicker now show the following applications:

Applications

So the example enables us to start/stop http services dynamically in one process and deploy/undeploy3 various RWT applications at those services. The latter uses the port property of the http service as binding selector. Quite nice I think :-) But actually it does a little bit more. Stopping and restarting the process shows that the latest configuration has been stored4. The system will start up the two services and deploy the RWT applications again to those services:

Relaunch

Behind the scenes

To be able to start and stop the http service instances we use the managed service factory implementation provided by the jetty5 control bundle. You can find the service in our example above using the services console command:

osgi> services org.osgi.service.cm.ManagedServiceFactory
{org.osgi.service.cm.ManagedServiceFactory}={service.pid=org.eclipse.equinox.http.jetty.config, service.id=40}
  Registered by bundle: org.eclipse.equinox.http.jetty_2.0.100.v20110502 [12]
  Bundles using service:
    org.eclipse.equinox.cm_1.0.300.v20110502 [6] 

Looking at the print out we also recognize the service.pid property which I use in the CommandProvider implementation to create a new http service configuration at runtime:

private Configuration createHttpServiceConfiguration()
  throws IOException
{
  ConfigurationAdmin configAdmin = getConfigurationAdmin();
  String location = findHttpServiceManagerLocation();
  String PID = "org.eclipse.equinox.http.jetty.config";
  return configAdmin .createFactoryConfiguration( PID, location );
}

The location is the location attribute of the jetty bundle that registers the factory. We can use the configuration created above to start a new equinox jetty based http service at a given port:

[...]
  Configuration configuration = createHttpServiceConfiguration();
  configuration.update( createHttpServiceSettings( port ) );
[...]

private Dictionary<String, Object> createHttpServiceSettings( String port ) {
  Dictionary<String,Object> result = new Hashtable<String, Object>();
  result.put( JettyConstants.HTTP_PORT, Integer.valueOf( port ) );
  result.put( JettyConstants.CUSTOMIZER_CLASS,
                 "org.eclipse.rap.jettycustomizer.internal.SessionCookieCustomizer" );
  return result;
}

The Configuration#update(Dictonary) method starts the service and persists its configuration. This allows the system to restart the service with the same configuration during the next lauch.

Note that the http service settings use constant definitions of the particular HttpService implementation. Therefore this will not work with another service implementation.

Now let us have a look at how to start and bind an RWT application to such an http service instance. The example provides several ApplicationConfiguration service declarations that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
  immediate="true"
  configuration-policy="require"
  name="helloWorld">
  <implementation
    class="com.codeaffine.example.rwt.osgi.configurationadmin.applications.HelloWorldApplicationConfiguration"/>
  <service>
     <provide
       interface="org.eclipse.rap.rwt.application.ApplicationConfiguration"/>
  </service>
</scr:component>

The interesting part for us is the property “configuration-policy” of the “component” tag. Setting it to “require” allows us to use the configuration admin to deploy RWT applications on various http services:

Configuration configuration = configurationAdmin.createFactoryConfiguration( configurationName );
configuration.update( createApplicationSettings([...], port, [...]) );

Where createApplicationSettings(…) creates the property that is used to bind the
application to a certain http service. The property uses the port number as selector in a filter expression. In case the binding should be done to an http service on port 10010 it would look like this:

httpService.target=(http.port=10010)

Conclusion

In this post I gave an impression of the possibilities using RWT in conjunction with the ConfigurationAdmin service. So if you want to play around with the stuff or want to look at the implementations in more detail simply pull the example from the repository. But keep in mind that the example is only meant for demonstration purpose and not intended to be production ready.

Now that we have seen how to start and stop RWT applications dynamically there is still the question of how to contribute UI elements dynamically to a running application – but this is a story I will probably cover in another post..

Last but not least I like to mention that a fellow developer, Ralf Sternberg, and I will talk at EclipseCon Europe about Dynamic Web Applications with OSGi and RAP. So if you interested and you happen to be at the event – don’t be shy, just drop by :-)

 


  1. Import the plugin project contained in the git repository into a workspace of your Eclipse IDE. The project contains a target definition (target.target). Open this file with the target editor, wait till the target resolving job has been completed and click on the Set as Target Platform link afterwards (If the target editor shows problems resolving the RAP runtime, select the according entry in the list and click the update button on the right). Last you should check out org.eclipse.rap.rwt.supplemental.fileupload and org.eclipse.rap.jettycustomizer from Eclipse CVS.
  2. help is actually not a command provided by the system but it does the trick anyway…
  3. The term deploy may sound a little bit oversized as the bundle containing the application declaration has already been installed. But in the context of this post the name should point out the fact, that launching an application contains the notion of binding it to a certain http service. This means we can launch the same application declaration more than once, binding each one to a different HttpService instance, where each application instance is completely isolated from the other regarding static resources and memory (The latter does not hold for static fields of course…).
  4. Ensure that the Clear the configuration area before launching of the Settings tab in the launch configuration is unchecked!
  5. SymbolicName: org.eclipse.equinox.http.jetty
Follow me

Frank Appel

Frank is a stalwart of agile methods and test driven development in particular. He understands software development as a craftsmanship based on a well-balanced mix of knowledge and the experience of the daily work.

fappel@codeaffine.com
Follow me

Latest posts by Frank Appel (see all)

Tags: , , , ,

One Response to “RAP/RWT-OSGi Integration II”


Leave a Reply