Propagating OSGi dynamism in web interfaces

This post is the third post of the dynamokos series. This post focuses on the propagation of OSGi dynamism into web interfaces. This became a critical issue, as new innovative and user-friendly web applications must be able to react to ‘server’ changes.

Inside this post

In this post, we see how to manage the dynamism inside a web interface by adapting the web view dynamically. According to the availability of the dynamokos oracle (a remote OSGi service), the page content is updated.
Three ways are investigated to support the dynamism namely,

  • the auto-refresh
  • the ajax pull
  • the comet push

Background

In the previous posts, we built a distributed OSGi application. The system is based on two platforms. The first one implements and exposes a Prediction service used by the second platform, which is responsible for the UI which is a web application.

In the first version, the ‘client’ platform was statically bound to the Prediction service. But this got us into issues when the Prediction service was no more provided (i.e. unavailable).

Architecture of the first version of the dynamokos application
Architecture of the first version of the dynamokos application

In the second version, we introduced dynamic discovery to deal with this issue. In other words, the client platform discovers the Prediction service and uses it. If there is none or it becomes unavailable, the web application is shutdown. However, this opens a new problem. When the prediction service is unavailable, the user receives a nice (Not!) 404 – Page not found error.

Architecture of the second version of the dynamokos application
Architecture of the second version of the dynamokos application
No web page when the oracle is out of his office
No web page when the oracle is out of his office

So, this last version is definitely not acceptable. This post describes how to improve this version by impacting the web interface when the availability of the Prediciton service changes.

Why managing the dynamism inside web apps?

Nowadays, web applications become more and more attractive and the provided user experience is close (if not better) to desktop applications. With the development of web 2.0 toolkits providing nice widgets and ajax capabilities, these applications react like native applications for the most part. But, one thing makes a critical difference: how and when to update the content of the page?

Let’s imagine a web-based collaborative text-editor. If two users edit the same document at the same time, they should be warned to avoid losing data.

On desktop application, we can easily imagine some asynchronous mechanism based on listener and/or message oriented-middleware (like JMS). But this is not possible on web application because the browsers do not have the permission to do that (if nothing else, such features would raise open security issues).

Unfortunate, as features like dynamic update are critical to improve the user experience of web applications and to avoid the really unpleasant and intrusive need for a refresh page action of the user.

The key to fix this issue is mostly the web page itself.

The auto-refresh approach

The first approach is really basic. It just asks the browser to periodically update the whole page.

Architecture of the dynamokos system with an auto-refresh
Architecture of the dynamokos system with an auto-refresh

To achieve that, you just need to instruct the web page to:

<meta http-equiv="refresh" content="5" />

By adding this line in the header part of the web page, it asks the browser to refresh the page every 5 seconds. As the web page checks the availability of the Prediction service during the loading, it checks the availability of the Prediction service every 5 seconds.

This way is pretty simple however,

  • Refreshing the whole page is pretty user unfriendly… e.g., it will loose form content (in your case the question).
  • It does not fix the issue if the service goes away between two refreshes and if the query is made before the content is updated.

Furthermore the meta-refresh was deprecated by the W3C.

The Ajax pull

The second way uses Ajax.
AJAX (shorthand for asynchronous JavaScript and XML) is a group of interrelated web development techniques used on the client-side to create interactive web applications or rich Internet applications. With AJAX, web applications can retrieve data from the server asynchronously in the background without interfering with the display and behavior of the existing page. The use of AJAX has led to an increase in interactive or dynamic interfaces on web pages and better quality of Web services due to the asynchronous mode. Data is usually retrieved using the XMLHttpRequest object.
Thanks to Ajax, it is relatively simple to deal with the dynamism of the Prediction service in the web page. All it has to do is to query the server periodically and adapts itself according to the result.

Architecture of the dynamokos system with an Ajax Pull
Architecture of the dynamokos system with an Ajax Pull

In our case, we just extend our servlet to support this new query. The servlet now returns ‘available’ if the Prediction service is available, ‘unavailable’ otherwise.

	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.getOutputStream().print(
			m_oracle == null ? "unavailable" : "available");
	}

Note: We choose doPost instead of doGet just to avoid mixing the two queries in the same method. But, it will make more sense to use doGet.
The web page is also modified to execute the query periodically and to adapt itself.

The adaptation is quite simple, and just toggles the attributes of the text area, button (set to disable) and the image (update the image source).

function updateUI (available) {
	if (available) {
		dojo.attr("qel","disabled",false);
		dojo.attr("askbutton","disabled",false);
		dojo.attr("imgball8","src","res/8ball.jpg");
	} else {
		dojo.attr("qel","disabled",true);
		dojo.attr("askbutton","disabled",true);
		dojo.attr("imgball8","src","res/Un8ball.jpg");
	}
}

The periodic pulling is also pretty simple to do:

var timer = new dojox.timing.Timer();
timer.setInterval(2000); // Interval in millisecond                 
timer.onTick = function () { 
	//  Execute the query and call updateUI.
}
timer.start();

Let’s try that. Download the –runtime archive from here. Unzip the downloaded archive and open three terminals to this location (in the runtime directory). This demo requires Java 6, so you will have to set your environment to Java 6 (if it’s not the default one).

Then, in the first terminal, launch the Zookeeper server:

Linux : sh ./zookeeper/bin/zkServer.sh start 
Windows: zookeeper\bin\zkServer.cmd start 

Then, in the second terminal, launch the server platform. We use the same configuration as for the last post:

java -Dfelix.config.properties=file:conf/oracle-dosgi-zookeeper.properties -jar bin/felix.jar cache/oracle-dosgi-zookeeper

Finally, launch the client platform in the third terminal:

java -Dfelix.config.properties=file:conf/client-dosgi-zookeeper-pull.properties -jar bin/felix.jar cache/client-dosgi-zookeeper-pull

Now open the dynamokos web page.

The Dynamokos Oracle UI
The Dynamokos Oracle UI

If you stop the Oracle bundle from the platform service with:

stop 11

The web page is ‘immediately’ updated:

The UI is updated when the Prediction service becomes unavailable
The UI is updated when the Prediction service becomes unavailable

Restart the oracle with:

start 11

The web app is functional again.

The UI becomes usable again
The UI becomes usable again

So, Ajax allows us to manage the dynamism and to propagate the server changes into the web page. However, this might overload the network if we have a lot of clients. Every 2 seconds the web page queries the server leading into potential scalability and bandwidth issues.
Number of request in the pull approaches
Number of request in the pull approaches

Moreover it does not fix the issue if the prediction service goes away between two ‘pulls’.

The comet push

The last way inverts the communication direction. Instead of forcing the page to interact with the server regularly, the server will push updates only when they are needed.

Architecture of the dynamokos system with Comet Push
Architecture of the dynamokos system with Comet Push

To do that, we use Comet. Comet is a neologism to describe a web application model in which a long-held HTTP request allows a web server to push data to a browser, without the browser explicitly requesting it. Comet is an umbrella term for multiple techniques for achieving this interaction. All these methods rely on features included by default in browsers, such as JavaScript, rather than on non-default plugins.
In theory, the Comet approach differs from the original model of the web, in which a browser requests a complete web page or chunks of data to update a web page. However in practice, Comet applications typically use Ajax with long polling to detect new information on the server.

Comet brings the last missing piece to web application to provide almost the same set of interactions as desktop applications.

In this application, we use the Bayeux protocol (supported by DOJO). It provides message-oriented-middleware concepts very close to JMS (i.e., message, topics…). However, Bayeux is based on a publish/subscribe model, so servers supporting Bayeux have publish/subscribe built-in. So, not all HTTP servers support this protocol yet.

The good news is that dynamokos provides an OSGi HTTP service supporting comet / Bayeux (Cometd). Moreover, it provides a bridge propagating events from the OSGi Event Admin to Comet and vice-versa.
Once this middleware is installed, using Cometd is pretty simple. On the servlet side, we just have to configure the bridge to send via a Event Admin topic to Cometd and vice versa. Then, to send a notification to the browser, we just have to send an event. Don’t worry if you don’t have any experience with the Event Admin. The iPOJO component model comes with a pretty great integration that makes using the Event Admin very easy.

First of all, we need to configure the Cometd Event Admin bridge:

    /**
	 * The Cometd Event Admin Bridge.
	 */
	@Requires
	private EABridge m_bridge;
	
	@Validate
	public void start() throws ServletException, NamespaceException {
		m_bridge.exportTopic("oracle/state", "/oracle/state"); // Progpagate EA events to comet
		m_bridge.importTopic("/oracle/require", "oracle/require"); // Propagate Comet events to EA

		// Expose itself
		http.registerServlet("/oracle", this, null, null);
		// Expose the web page
		http.registerResources("/dynamokos", "web", null);
	}

So, we use the EABridge service to configure the bridge. We ask him to propagate events from the Event Admin using the /oracle/state topic to cometd using the same topic. Next, we send events to the Event Admin when the Prediction Service availability changes:

	/**
	 * Publish event son the event admin thanks to the ipojo event admin handler.
	 */
	@org.apache.felix.ipojo.handlers.event.Publisher(name = "p1", topics = "oracle/state")
	private Publisher m_publisher;

       /**
	 * iPOJO injects the Prediction service in this method when it's available.
	 * 
	 * @param oracle
	 */
	@Bind(optional = true)
	private void bindPrediction(Prediction oracle) {
		m_oracle = oracle;
		available(true);
	}

	/**
	 * iPOJO injects the Prediction service in this method when it's unavailable.
	 * 
	 * @param oracle
	 */
	@Unbind(optional = true)
	private void unbindPrediction(Prediction oracle) {
		m_oracle = null;
		available(false);
	}
	
	/**
	 * Publishes the availability of the oracle.
	 * 
	 * @param state
	 */
	private void available(boolean state) {
		Dictionary<String, Object> data = new Hashtable<String, Object>();
		data.put("available", state);
		if (m_publisher != null) {
			m_publisher.send(data);
		}
	}

Thanks to the (iPOJO-) injected Publisher object, it is very easy to send events. We just configure the topic and then use the send method on the object.

That’s it for the servlet !

The web page has to be slightly modified to support cometd interactions as well:

dojo.addOnLoad(function() {
        dojox.cometd.init("http://localhost:8080/cometd");
        
        dojox.cometd.subscribe("/oracle/state",function(message){
          updateUI(message.data.available);
        });
}

The init function initializes the handshake between the server and the browser. Next, we register a callback on the /oracle/state topic updating the UI.
Now, It’s time to run the demo.
Stop the client platform from the previous example (type ‘shutdown’ in the console). Then launch:

java -Dfelix.config.properties=file:conf/client-dosgi-zookeeper-cometd.properties -jar bin/felix.jar cache/client-dosgi-zookeeper-cometd

This launches a new server platform with the Cometd capable HTTP Service and the EABridge.

Open the dynamokos web page, and then stop the oracle by executing ‘stop 11’ in the server platform. The web page is immediately updated. If you restart the oracle (start 11), the page is updated. What happened is pretty interesting:

The oracle is stopped, the discovery service removes it from zookepper, notifying the client platform of the departure. So, the proxied service is unregistered from the OSGi service registry. iPOJO calls the unbind method from the servlet, which sends an event to the event admin (on the /oracle/state topic) notifying about the availability change. The event is dispatched to the event admin listeners and more precisely to the EABridge. Subsequently, the EABridge asks the HTTP Cometd capable server to notify the interested browsers of the change. Our browser is interested and so receives the event and updates its UI.

This approach also reduces the number of queries:

Number of request in the push approach
Number of request in the push approach

Conclusion

This concludes the third post of the dynamokos series. In this post, we did see three possibilities to deal with the OSGi dynamism inside web applications. First, we showed how to do that with an auto-refresh. Next, as this solution is definitely not optimal, we showed how to achieve the same thing with a periodic Ajax pull. This solution is much better, but can overload the network — hence, finally, the cometd version which profits from state-of-the-art Comet interactions to enable server to browser communication.

This post also introduces the EABridge enabling event propagation between cometd and the OSGi event admin. This component comes from the OW2 Chameleon Rose project, which will be the focus of the next post. ROSE is a powerful, flexible, and technology-agnostic framework for OSGi distributed services.

If you have questions, feel free to post a comment on this post or to contact us.

Acknowledgment

I would like to thank Jonathan Bardin from the Adele group (Grenoble University) for his help about the Ajax Pull and Comet.

3 thoughts on “Propagating OSGi dynamism in web interfaces

  1. Pingback: learn

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s