RAP/RWT-OSGi Integration III

Home  >>  Eclipse  >>  RAP/RWT-OSGi Integration III

RAP/RWT-OSGi Integration III

On October 13, 2011, Posted by , In Eclipse,OSGi, By ,,,,, , With 2 Comments

The previous posts 1 about the new RWT-OSGi integration bundle of RAP 1.5 concentrated on the various possibilities of how to run RWT as Web-UI-Toolkit in OSGi environment. In this post I will discuss some ideas of how to use RWT and OSGi to build dynamic web applications. To do so I have upgraded the example application2 I use throughout this mini series.

The Example

Again I start with a short walk through of the example’s main functionality. The main development concepts behind the scenes are covered in the next section. Once you have imported the example projects into your Eclipse workspace you can use the RWT-OSGi-ConfigurationAdmin launch configuration contained in the configuration admin project to start the example.

As shown in the last post we can use the following console commands to start the example application:

startHttpService 10010
deployApplication ExampleUI1 10010

We are able to access this application in the browser using the URL “http://localhost:10010/example”:

The screenshot above shows basically an empty web application frame that is bare of any content yet. To change this use the following console command:

deployUIContribution HomePageTab ExampleUI1 10010

Well, on first sight the changes are not that impressing either. But actually the command added dynamically content to our application:

Dynamic Contributions

Using the command “ss” at the “osgi>” prompt provided by our UI contribution clarifies what our contribution is all about:

OSGi Console

Having a console session available in our web application we can use it just as well to contribute further functionality. Using the command as shown in the following screenshot…

Start Bundle Upload Contribution

… contributes a new UI element to the application:

Upload Contribution

I think that is enough to grasp the basic idea of the example, so let us have a look into some of the programming details.

Behind the scenes

In our example application we use a little helper called UIContributorTracker3 to contribute content dynamically to RWT based web applications4. As the name implies it tracks UI contributions provided by instances of UIContributor. UIContributor implementations are meant to be used as UI builders and each contribution type is declared as OSGi service. The UIContributorTracker implementation uses a ServiceTracker to track the lifecycles of such contributions.

public interface UIContributor {
  String getId();
  Control contribute( Composite parent );
}

As you can see the contributor interface is straight forward. It demands an identifier that can be used by implementations of user interaction5 to identify and activate a certain contribution. Furthermore it provides the actual builder functionality that allows to embed UI contributions into the RWT based web frame application. A simple implementation may look like this:

public class HelloWorld implements UIContributor {

  @Override
  public String getId() {
    return "Hello";
  }

  @Override
  public Control contribute( Composite parent ) {
    Label label = new Label( parent, SWT.NONE );
    label.setText( "Hello World" );
    return label;
  }
}

The respective OSGi service declaration will look like this:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
  name="HelloWorld"
  configuration-policy="require">
  <implementation
    class="com.codeaffine.example.rwt.osgi.ui.example.HelloWorld"/>
  <property name="type" type="String" value="page"/>
  <service>
     <provide
    interface="com.codeaffine.example.rwt.osgi.ui.platform.UIContributor"/>
  </service>
</scr:component>

Nothing spectacular in it especially if you are familiar with the previous posts. We use the configuration-policy to keep the declared service dormant until it is explicitly invoked by the configuration admin service. The property “type” will be used in an LDAP filter expression to distinguish between different kinds of UI contributions. In the “HelloWorld” case above we decided that the contribution is used as an additional page. In our example webapp page contributions are presented to the end-user as selectable entry in the navigation bar.

Using the following command…

deployUIContribution HelloWorld ExampleUI1 10010

… will integrate the “HelloWorld” contribution into the running example instance:

Hello World Contribution

That was not too difficult, was it?

Before comming an end I want to point out some of the noteworthiness things about the UIContributorTracker mentioned above.

  • The tracker is intended to be extended. Implementers may override e.g. the. addingService() method.
  • The tracker implementation relies on an OSGi ServiceTracker that is registered as an OSGi service itself. UIContributorTracker instances gain access to UIContributor services using this global tracker service. This approach allows that each contributor has only one reference counter and can be deregistered again easily. Contributor registration and deregistration events are broadcasted to the registered ContributorTrackers. So despite of the name the UIContributorTracker is not an OSGi service tracker.
  • The tracker implementation already takes care of the background threads that notifies about service lifecycle changes. Updates of RWT UI elements are only allowed using the appropriate UIThread. Therefore the tracker decouples the background thread from the actual work of creating the UI parts using a callback functionality provided by RWT.

Here is a snippet that shows how the tracker can be used:

@Override
public UIContributor addingService( ServiceReference<UIContributor> reference, UIContributor service ) {
  if( ConfiguratorTracker.matchesType( "BundleUpload", reference ) ) {
    bundleUploadContributor = service;
    updatePage();
  }
  return result;
}

The code above shows how the added UIContributor service is used only in case of a matching contribution type. As mentioned above the contribution type is specified as a service property e.g. at service declaration time. The contributor is buffered6 and the call of updatePage() will supplement the contribution to the current page content by calling UIContributor#contribute(Composite) on the given contributor instance.

Conclusion

Although we do not have an out of the box application framework to create OSGi based web applications with RAP/RWT at the moment, I showed that there is already a lot of infrastructure available and with a little hands-on skills you can build some quite effective web apps on top of it7.

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. We also have a tutorial slot Lightweight, Dynamic Webapps Made Easy with RAP and OSGi that will go more into details of things. So if you interested and you happen to be at the event – don’t be shy, just drop by :-)

 


  1. RAP/RWT-OSGi Integration, RAP/RWT-OSGi Integration II
  2. https://github.com/fappel/RWT_CONFIG_ADMIN_EXAMPLE: Import the plugin projects contained in the git repository into a workspace of your Eclipse IDE. The configuration admin 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.
  3. This class is located in the com.codeaffine.example.rwt.osgi.ui.platform project.
  4. Unfortunately an explanation of how to build a web application frame with RWT from scratch exceeds the scope of this post
  5. such as clicking on a navigation bar entry
  6. The code snippet stores the contributor to a field of the surrounding UIContributor. Although this works in our simple example it is not a good idea. Since UIContributors are shared globally setting the field would impact all UIs where the surrounding contributor is used. Therefore a production ready solution has to use a little more sophisticated approach…
  7. But keep in mind that all the UI platform code I used in the example is experimental stuff and is not intended to be used in production. But otherwise you are welcome to play around with it and come up with some new and intriguing ideas :-)
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

2 Comments so far:

  1. [...] Link: Frank Appel: RAP/RWT-OSGi Integration III [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>