However, one model that seems to emerge is web based UIs. The advent of DHTML, Javascript, and SVG provide an extremely rich environment for application development. Unfortunately, Javascript is not a nice language to handle large and complex problems. Many companies solve this by using webservices to distribute the work between the graphic user interface (GUI) and a server. Web services are remote procedure calls done over the HTTP(S) protocol. This model is reasonably well supported by Javascript using the XMLHttpRequest object.
Th web services model maps very well to an OSGi service platform. In a way, you just need a way to easily call the services in the OSGi service registry from Javascript. So how would such an application look like?
Let us first layout the bundles I like to think in bundles because it is nicely concrete and down to earth. We obviously need a web server, which is easy to fulfill with the OSGi Http Service. We then require a bundle to handle the grunts of the remote procedure calling and another bundle to prove that it works.
The rpc calling bundle has the responsibility to handle the remote procedure calls from Javascript and map them to calls on an OSGi service. I’ve called this bundle webrpc. The second bundle is the demo application. This summer I emotionally blackmailed my son Thomas to learn how to write a program; he caved in and wrote a working Sudoku game in Java after a false start in C++. This exercise gave me more experience with the Sudoku domain than I ever wanted to have so the demo will be a sudoku bundle.
The webrpc bundle should not indiscriminately export services. There are obviously security issues but also not all services are well suited to be exported. However, we’d like to keep the service as simple as possible. The choice was made to look for the public property on the service registration. This is easy to set with declarative services and it means we can use a POJO as our service; the service itself is not involved with the remote procedure calling. The value of the property is the name under which the service should be known to the outside world.
I could have used a complete web services stack, there are an amazing amount of those applications available, almost all written in Java. However, I wanted to run the demo on my Nokia E70 phone that runs an OSGi service platform. Memory is only abundant on PCs and services, so a complete web services stack can add up. It also adds up on the Javascript side because a compliant web services stack is non-trivial. I therefore decided to optimize space and implement a very lite model of RPC over HTTP. Requests are done using the HTTP protocol. The path provides the service and its method, while the query parameters provide the arguments. I used 0 for the first argument, 1 for the next, and so on. For example:
http://localhost/rpc/sudoku/newGame?0=simple
This request will invoke the newGame method on the service that is registered with the property public set to “sudoku”.
The webrpc bundle depends on the Http Service. When there is an Http Service present, it registers itself under the /rpc alias. The servlet will get called for all requests that start with /rpc. For such a request, the webrpc bundle looks up the service name (in the example sudoku) in the service registry using a simple query string with the OSGi filter language to do this. The next part is calling the right method in this service; this is non-trivial because it is necessary to coerce all the arguments from strings into the method argument types. I wrote a separate Invoker class to handle this coercion. Read it and weep. Most of the work is handling Java’s silly primitives.
When the method has been called it returns an Object. This object must be shipped back to the Javascript in the browser. Now the gut reaction of most programmers is to think XML. Not me this time, there is another standard called JSON that is so much easier for Javascript. It is a representation of strings, numbers, arrays, and maps that is compatible with the Javascript syntax. Converting an object into JSON is quite straightforward for values like numbers, strings, maps, and arrays; references to objects are a bit harder but that is a nice subject for another article. The JSON value is then returned as the body of the HTTP response. The Javascript will receive this text body and compile it to Javascript arrays, values, and dictionaries. From the Javascript point of view it can not be simpler.
The webrpc bundle maps requests that do not look like a method name to a getResource() call on the service object’s class. A service implementer can place all its web resources in the www directory and they are automatically mapped. That is, if someone requests /rpc/sudoku/prototype.js, it will load the resource from aQute/sudoko/www/prototype.js. Assuming the implementation class is in the aQute.sudoku package.
All this effort in the webrpc bundle has makes the sudoku bundle almost trivial. Well, I guess it was trivial in the first place because the server only calculates the board and this is not rocket science. The Soduko service only implements a newGame method. This method returns an array of 81 integers (remember how 9x9 was?). Negative integers mark positions that can be shown from the beginning; positive integers are to be guessed by the player. For the HTML side I decided to make a splash screen in SVG. Hey! We now have those fantastic tools, so let us use them. Though splash screen sounds more dramatic than it turned out, I admit, I am a lousy artist.
For the handling of the HTML and http requests calls I am using prototype.js. The Javascript and HTML is actually quite small. The Sudoku board is completely drawn in HTML and formatted using XML. When the Javascript starts up, it requests a new game from the Sodoku service. When this information (asynchronously) arrives, it formats the board with the received information. Rather cool in this model is the use of Cascading Style Sheets (CSS). CSS makes the mundane detail of formatting all the little details nicely manageable; however, remember I am not an artist so the looks can be improved.
Both the webrpc and sudoku bundles used declarative services. The webrpc bundle was hard to test standalone because it relies heavily on the OSGi service registry. The Sudoku service was however a POJO and could therefore easily be tested.
Try it out! If you think it looks too big, just make the window smaller. Notice how nicely it all scales because CSS and SVG are used to adjust all parameters to the window size.
You can download the bundles from the OSGi Bundle Repository (OBR). The JAR’s contain the source code of the bundles in the OPT-INF/src directory. See how extremely little code is required to achieve the goals. Enjoy!
Peter Kriens
Nice article Peter.
ReplyDeleteBut, I had had trouble using Web Interfaces because the browsers in devices are not "standard" compliant. If the client is firefox or IE sure you can use SVG, DHTML, ajax and so on, but in mobile phones or PDAs would we have these functionalities? Your browser in the nokia has SVG? and run prototipe.js without problems?
You really recommend this kind of GUI to work in mobiles? What is your experience with these devices. I'll appreciate any advice...
Again Thanks a lot
James Valencia
Very nice, this is exactly what i was looking for. But somehow i cant seem to find the sourcecode, only the class files
ReplyDeleteVery cool stuff indeed.
ReplyDeleteIf I understand it correctly, your code functions as a bridge, or RPC-like system to allow code in java OSGI bundles to be called from Javascript, right?
What about writing the OSGI bundle itself in Javascript? You may be interested to know that the people from Eclipse seem to be working on that right now:
Eclipse E4/Javascript
I've written an article about that myself (shameless plug :-):
OSGI for Javascript
Keep up the great work! OSGI rocks!
Oops, something went wrong with that last link... should have been:
ReplyDeleteOSGI for Javascript