Tuesday, November 24, 2009

OpenSocial (iGoogle) gadgets in Eclipse

Some of you may have seen this already, in the e4 M2 new & noteworthy document: We are bringing Eclipse and the Web closer together. This work, a collaboration between Benjamin Cabé of Sierra Wireless and myself, is happening in the e4 project, which is the incubator area where we work on new technology, mostly for the Eclipse SDK 4.0 release planned for Summer 2010. (Some of the technologies developed in e4 may make it into the 3.x stream1 as well.)

Concretely, we are opening Eclipse for a whole new world of UI components called OpenSocial gadgets. You have probably seen gadgets in action already, on iGoogle homepages. You can find gadgets that, for example:
  • display your Remember the Milk to-do list,
  • show your Twitter feed (with updates every x minutes),
  • provide your GMail inbox,
  • show a calendar, or, most importantly:
  • display the "cat photo of the day". :-)
Normally, gadgets would be hosted inside iframes on a web page. A web page that hosts gadgets, usually with the help of some server-side infrastructure, is called an OpenSocial gadget container. Many social websites are OpenSocial gadget containers - in fact, it looks like every social website except for Facebook is an OpenSocial gadget container - for example iGoogle, hi5, LinkedIn, MySpace, orkut, Friendster, Ning, XING and many others. Check out the OpenSocial web site and scroll down for the full list. Most (if not all) of these sites use the Apache Shindig reference implementation.

In Eclipse, OpenSocial gadgets are hosted as views. This is what it looks like:



More information, including how you can contribute, is available on this wiki page. You can also download e4 M2 and play with it, or install the feature into a 3.5 or 3.6 build as described on the wiki page.

I think this is really exciting, and potentially an important part of the future of Eclipse. Here is why:

1. It makes it easy to add a new view (or editor) to Eclipse. Just write HTML, CSS, and JavaScript, and you don't even have to know that the gadget is going to be hosted in an Eclipse application. All the usual web arguments apply - zero install, all you need is a URL, proper sandboxing, etc.

2. It brings Eclipse and the "Open Web" closer together. Web UIs are becoming increasingly important, and who knows, we may at some point want to run a full-blown IDE in a browser. But until then, we need a way to take advantage of the web without losing everything that we already have - supporting the existing Eclipse plug-ins is important for the forseeable future. By bringing the web to Eclipse instead of bringing Eclipse to the web, we can get the best of both worlds, if we can ensure that gadgets can become first class citizens in a desktop Eclipse application. (See 4. for what I mean by "first class Eclipse citizen".)

3. It can make Eclipse more social. At this point, our implementation does not support the "social" part of OpenSocial gadgets, but if we added that support, it could serve as another integration point for plug-ins, similar to how the common resource model (projects/folders/files) is an important "common currency" for IDE plug-ins.

4. The OpenSocial specification could benefit, too. We have ten years of experience with Eclipse as a platform or, as I like to call it, as a client-configured mashup platform. Users can start with a minimal platform, add a whole bunch of plug-ins and get an application where individual pieces work together seamlessly. (OK, I admit, it's not seamless in some cases, things don't always work together well, and if you add an insane number of plug-ins, Eclipse is slow and bloated, but I hope you get the idea.) I honestly don't know which other platform has come as far as Eclipse has in terms of integration of heterogeneous components. If you look at examples of the kind of integration and seamlessness I list below, only the first two are currently addressed by the OpenSocial gadgets specification. Many of the other "integration points" that we offer in Eclipse would make sense for OpenSocial as well, if the goal is to support more than a bunch of independent gadgets that sit next to each other on a web page. Here is a partial list of what we call the Eclipse Application Services a.k.a. "the twenty things":
  • Editing preferences in a consistent way.
  • A common mechanism for localizing strings.
  • Providing and listening to the current window-level selection.
  • Being able to start long-running operations, with progress reporting and the ability to cancel.
  • Indicating unsaved changes and prompting to save on close.
  • Common undo and redo operations.
  • Persisting UI state (e.g. column widths, sorting, etc).
  • Error reporting.
  • Common dialogs for common tasks.
  • Contributing menu and toolbar items to a shared area (global menu or toolbar), or even to other views and editors in form of additional items in local menus or toolbars.
For the full list in draft form, and more details, check out the Eclipse Application Services wiki pages. Ignore the fact that most of these wiki pages describe API in Java - it wouldn't be hard to specify similar or equivalent API in JavaScript as well. We still have to find out how best to interact with the OpenSocial community, and if they would be interested in taking their spec to the next level as hinted at above.

On the Eclipse side, our plans for the coming weeks and months are roughly the following:
  • Complete and solidify our implementation, which currently has high duct tape content.
  • Investigate if we can reuse parts of Apache Shindig to make our job easier.
  • Offer Eclipse Application Services as so-called "features" that gadgets can (optionally) depend on.
  • Write example gadgets that show the kind of integration into Eclipse that we'd like to see.
Do you have an idea for a gadget that you would like to see in Eclipse? Would you like to join the fun and become an e4 committer to work on this with us? Let us know on the e4-dev mailing list if you would like to participate, or send me a direct email. Bugs and enhancement requests can be filed in Bugzilla.

Plain old comments on this blog are welcome too, of course. ;-)




1 - Similar to what Apache did with its httpd project and the 1.3.x and 2.x streams, we are planning two Eclipse SDK streams going forward - regular releases on the 3.x stream (3.6, 3.7, 3.8 ...) with a focus on stability, and a parallel 4.x stream with the innovative stuff.

Sunday, October 25, 2009

Adventures into web UI land

To explore how easy or hard it would be to write a UI component using web technologies, and then integrate it as a first class citizen in Eclipse, I reimplemented the PDE "site.xml" editor for the 0.9 release of e4, using HTML, JavaScript, Dojo, and CSS.

I thought it would be interesting to document the design decisions that I made for this. Since my experience with web UIs is somewhat limited, you should take the following with a grain of salt. I did, however, work on something that could be characterized as an "IDE in a browser" for over three years (2001-2004), so I don't consider myself a complete rookie. :-)

Note that I won't talk about integrating the web UI component into Eclipse, this posting is just about the actual web UI component itself. The Eclipse integration is a related, but different story, that deserves its own post.

Let's start with a screenshot of the original PDE editor. It has two panes, a tree on the left showing features and categories, and a bunch of fields on the right with which you can edit the currently selected object in the tree. Depending on the type of object, the right side shows different fields, for example feature environments if the selected object is a feature, or category ID, name, and description if the selected object is a category. To add new categories or features, there are some push buttons on the right side of the tree.



We should be able to achieve a very similar look and feel with a piece of web UI, after all, the "flat look" of the PDE editors was an attempt to mimic the look of a web page.

The first important decision I had to make was whether to generate the HTML, pre-filled with the data, on the server side. This has the advantage that the resulting HTML can be made to (somewhat) work even if the web browser displaying it has JavaScript disabled. You would probably use a server-side template engine for this. If you follow the link, you can see one of the disadvantages of this approach - there are a bajillion template engines to choose from. Good luck with deciding which one! ;-)

But seriously, I had other reasons for deciding to let client-side JavaScript fill in the data instead. For example, this approach scales better because the "filling in data" work is done on the client, with the server doing less work because it only serves raw data. Also, it makes it easier to handle dynamic changes to the data on the client side because there is only one way of turning data into populated widgets. Development and testing is easier because you avoid a complete layer of the cake - you don't need to restart the template engine or reload the template every time you make a change, instead you change the .html or .js file and reload the page in the browser. Finally, this approach quite naturally leads to an interface between client and server that could be used by other kinds of clients as well (you get an API if you decide to publish and maintain it).

Oh and I forgot, it wouldn't be buzzword compliant - to claim you're doing Ajax means that you have to use JavaScript and XMLHttpRequest, and to be RESTful means that the server should serve raw data.

I started with the HTML and CSS first, leaving the client-server communication for later. My first goal was to get the right kind of "look". Many things are easy to do in plain HTML, for example input fields and buttons, and the header area that says "Update Site Map". There were two things that are hard (or maybe impossible) with plain HTML: making the two panes resizable by the user, and displaying a tree of objects. I decided to use Dojo for these two things, because I had a little previous experience with Dojo, and because it had been IP-approved for use by Eclipse projects. Note that I didn't use Dojo widgets for buttons and text fields, mostly because I didn't like their Dojo-styled look and wanted the "plain" look that you get from plain buttons and plain text fields.

For the resizable panes with a draggable splitter between them, I was able to use a Dojo BorderContainer, which is configured like this:
<div dojotype="dijit.layout.BorderContainer" design="sidebar"
livesplitters="false" gutters="false"
style="width: 100%; height: 90%;">
The tree is created dynamically from JavaScript as follows:
myTree = new dijit.Tree({
id: "myTree",
model: model,
showRoot: false,
getLabel: function(item) { /* code to return the label... */ },
getIconClass: function(item, opened){
/* code returning a CSS class for the icon */
},
onClick: function(item,treeNode) { /* ... */ }
});
myTree.startup();
dojo.byId("tree").appendChild(myTree.domNode);
This creates a tree widget based on the model you are passing in, and puts it under the DOM node with the ID "tree". Of course, there is more code than what I am showing here, but I hope that the few snippets I am showing give you enough context to understand the rest.

I initially ignored the server part completely and just hard-code some example data right in the JavaScript. This allowed me to rapidly test and develop the web UI in a browser. Actually, make that "in all the browsers I cared about". During development, I kept Firefox, IE, and Safari open to make sure it worked in all of them. Some of the things you'd like to do in CSS, in particular with respect to layout, don't work quite the same in all the browsers. :-)

Here is the result, opened in a standalone web browser:



My next decision was about the client-server communication. I decided to use JSON as the data transfer format, because, as you all probably know already, "JSON has become the X in Ajax" (quote: Douglas Crockford). There was a more pragmatic reason, too: the version of Dojo that I used was a bit older and didn't support trees backed by XML data. With a little help from Dojo, you can make HTTP requests without having to worry about browser differences.

There is only one thing that is not obvious: if the web UI is in a file like "site-editor.html" that references the necessary CSS and JavaScript pieces, then how does it know its "input", i.e. which resource to operate on? Somehow, the web UI needs to get to know the full path to the site.xml file. One widely used approach for solving this problem is to (mis-)use the "anchor" part of the URL that the browser points at. So for example, if the browser's URL is http://localhost:9234/pde-webui/site-editor.html#/myproject/site.xml then it will request /pde-webui/site-editor.html from localhost:9234, followed by an attempt to find the anchor named /myproject/site.xml in the HTML. Even though it won't find this anchor, the document.location object will contain the full information. This means that our JavaScript code can just get the value of document.location.hash and then make a corresponding XMLHttpRequest to get data from the server, which it then uses to fill the widgets. Once you know about this technique (which by the way has some nice properties with respect to the back button and the browser history), you will start to notice its use in many existing and widely used web-based applications. Like for example, https://mail.google.com/mail/#inbox, or http://www.facebook.com/home.php#/bokowski?ref=profile :-)

By now, if you are still following, we have a client-side web UI consisting of some HTML, CSS and JavaScript, that will access a server over HTTP to get the data that needs to be displayed. Let's now focus on the server part.

Obviously, we need a place to serve our static .html, .css, and .js files. The canonical choice for this is to configure Jetty accordingly. I am instantiating my own instance of Jetty and instruct it to pick a port number for me. If I know that the web UI will only be accessed from the local machine, Jetty can be configured to only accept connections from localhost.

For the RESTful interface, I implemented a servlet that
  1. responds to a GET request with the data I need in JSON format, and that
  2. accepts PUT requests when the user wants to save changed data.
In reality, the servlet does a little more (like e.g. authentication), but this post is already pretty long and I need to gloss over some of the details to not bore everyone to death.

Let me just add one more thing - how did I implement the part of the servlet that converts the site.xml file into the JSON format I needed?

The most obvious approach would be to parse the XML as a DOM and then generate JSON based on that DOM. Instead, I decided to use EMF objects as an intermediate "format". My idea was that by using EMF, the example code could easily be adapted to any data model that's already EMF based, and XML files (assuming they have an XML schema) could then be considered a special case.

If you have an XML schema, you can let EMF create an .ecore file for you (using the New EMF Project wizard). For my use case, I chose to not generate any Java code from the .ecore file, because the code that generates JSON works on any EMF model, using generic EMF calls. This means that it should be very easy to change the schema, or even to use the same code for completely different models.

Just to be clear, if you know that the format of your XML never changes, or if you want to minimize the external dependencies of your code, or if you enjoy programming against the DOM API ;-), or if adding EMF as another "layer" disturbs you, it's perfectly fine to not use EMF. Maybe it would even make sense to use XML on the client side as well.

Overall, I was pretty happy with the structure that I came up with and think that it can serve as an example of how to approach the task of writing a web UI component. And now I'm looking forward to your comments, especially ones that explain how I could have made better decisions!

Thursday, October 15, 2009

JSR 330 (Dependency Injection for Java) passed!

Two days ago, JSR 330 passed its final vote, and we now have a standard way to annotate Java classes for dependency injection. Thanks to the spec lead Bob Lee, the JSR 330 expert group did its work in record time, in the open, and under one of the most permissive licenses.

Because of the transparency of the expert group work, it is no secret that I am representing IBM in that group. I even implemented the spec in order to understand it better, and made that implementation available as open source in the context of the e4 project, which is the place where Eclipse Platform folks can experiment with new technologies. (Btw, I intend to put javax.inject in Orbit for use by other Eclipse projects.)

I am happy with the current state of JSR 330 and am looking forward to working with the expert group on a planned maintenance draft that will define a portable configuration API. Because with such an API, it will be possible to reuse application code across different injector implementations.

Note that postings on this site are my own and don’t necessarily represent IBM’s positions, strategies or opinions. Similarly, IBM's votes on JSRs don't necessarily represent my personal positions, strategies, or opinions. ;-)