Links

pmuellr is Patrick Mueller

other pmuellr thangs: home page, twitter, flickr, github

Saturday, March 11, 2006

More Eclipse Monkeying

Playing with Eclipse Monkey

I spent a little time playing more with Eclipse Monkey yeserday. I've written a little Domain Object Model (DOM) that allows you to load and execute a JavaScript file. The idea is to create some little reusable functions / classes. The first quick test was writing an alert() function. Here's the source of alert.js:

//------------------------------------------------------------------- // a port of web browser's alert() function //------------------------------------------------------------------- alert = function (message) { Packages.org.eclipse.jface.dialogs.MessageDialog.openInformation( window.getShell(), "Eclipse Monkey Alert", message ) } alert

What's going on here is that I'm defining a function that puts up a dialog with some message in it. The last line of the file references the function, and ends up being the 'result' of executing the script with my DOM. Let's show the example that uses this in the file alertTest.em:

/* * Menu: Test > alert * DOM: http://localhost/org.muellerware.eclipsemonkey.dom.scriptloader */ alert = ScriptLoader.loadProjectFile("ScriptLoader Sample", "monkey/alert.js") function main() { alert("Hello, World") }

Taking it from the top, the Menu: line will cause a "Test" menu to be created under the Monkey Script menu on the main window, and then add a menu item to that called "alert".

The DOM: line points to my DOM. I cheated; the 'value' of the line is supposed to be a URL to the update site to get the DOM. The last path segment in the URL names the bundle the DOM is implemented in. As long as that bundle is loaded, the previous part of the URL isn't used for anything.

The next line with the alert assignment loads the script defined previously. Since that script 'returns' a function, we store the function in a variable called 'alert'. Note that the uses of alert in both files is completely independent. The name used in the alert.js file is basically thrown away. The only thing remembered in that script is the 'return' value. After the assignment from the result of the loadProjectFile() method, we can use the alert() function anywhere else in the .em file.

Pretty cool.

My next thought was to create a Console class which provided access to an Eclipse console. I thought this would be a nice way to support some basic println() capabilties. And would be pretty simple to test.

Here's the source for my Console.js class:

Array = java.lang.reflect.Array ConsolePlugin = Packages.org.eclipse.ui.console.ConsolePlugin MessageConsole = Packages.org.eclipse.ui.console.MessageConsole MessageConsoleStream = Packages.org.eclipse.ui.console.MessageConsoleStream //------------------------------------------------------------------- function Console(name) { var console = new MessageConsole(name, null) this.messageConsole = console this.messageStream = console.newMessageStream() var consoles = Array.newInstance(MessageConsole, 1) consoles[0] = console ConsolePlugin.getDefault().getConsoleManager().addConsoles(consoles) } //------------------------------------------------------------------- Console.prototype.print = function(string) { this.messageStream.print("" + string) } //------------------------------------------------------------------- Console.prototype.println = function(string) { this.messageStream.println("" + string) } //------------------------------------------------------------------- Console.prototype.println = function() { this.messageStream.println("" + string) } //------------------------------------------------------------------- Console

And here's the tester:

/* * Menu: Test > Console * DOM: http://download.eclipse.org/technology/dash/update/org.muellerware.eclipsemonkey.dom.scriptloader */ alert = ScriptLoader.loadProjectFile("ScriptLoader Sample", "monkey/alert.js"); function main() { var Console = ScriptLoader.loadProjectFile("ScriptLoader Sample", "monkey/Console.js") console = new Console("testing, 1, 2, 3") alert(console) console.print("1") console.print("2") console.print("3") console.println() console.println("1") console.println("2") console.println("3") }

Bad news. Looks like I'm unable to load the MessageConsole class. As near as I can tell, the issue is that while running an Eclipse Monkey script, you only have access to stuff that the plugin that runs the script has visibility to. That plugin is org.eclipse.eclipsemonkey. You can change this, to some extent, with your own DOM, as it can see whatever it wants. However, that doesn't help in the JavaScript code, only in the Java code that implements your DOM.

Dang. The whole reason for doing my scriptloader thing was to try to radically cut down on the amount of Java you would need to write interesting scripts. I can see we are limited by strict classloading rules the eclipse runtime lays down on us. Which you can 'relax' by writing your own plugins. Which kills the idea of radically cutting down the amount of Java you need to write.

Sigh.

Wednesday, March 08, 2006

Web Services != Distributed Objects

I got a chance to talk to Arthur Ryman last month, for a few minutes, so took full advantage of the situation and launched into a rant/whine on WSDL. I gave him a brief synopsis of what we're trying to do on the project I'm working on (can't talk about it right now, sorry), and he made an interesting statement. "You're trying to use Web Services to do Distributed Objects. You should think in terms of document exchange instead." Not an exact quote, but pretty close.

I've been thinking about that a lot lately.

He's right, and he's wrong. We are/were trying to do distributed objects, and I really should know better than to even think about this. I've done CORBA ORB implementations, and worked on IBM's VisualAge Distributed Smalltalk project. Been there, done that, know it's a freaking mess. Even when you get it technically working, it becomes difficult to disentangle your object mess with your distribution mess. I've never seen it work well. So, he's right in that we shouldn't be doing distributed objects.

Where I think he's wrong is that we have to think in terms of documents. If you're doing nothing but storing documents, I guess it's fine. But really, we got clients wanting to talk to servers and presumably they want to send data back. Not documents. Then I have to map a document to data and back. Ick. Especially when the 'spec' way to do this is with the unbelievably horrible xsi spec (sorry Dave, I'm not smart enough for this stuff, or maybe I'm too old).

That's why JSON intrigues me. Data. Yummy, yummy, data. And really, I think you could take a view of Web Services using XML as a problem looking for a solution. There are few languages where mucking with DOMs is in any sense fun. I even had a chance to play with REXML last night, and, while I can write some pretty compact code to do interesting stuff, I still need to understand either DOM or XPath to do it. XPATH is another one of those things that's almost too hard. I can remember the easy bits, but then always need to go back to the inscrutable spec to get my work done. Ick.

Another interesing use case for the JSON stuff is returning arbitrary SQL result sets over the wire. If you want to XML-ize this, in such a way that you can easily WSDL it up, and have programming language bindings that are at all usable, you end up with a story where you have something like an SDO that wraps all your objects. And then the XML looks like crap, and just adds more overhead. The answer: remove the strict typing requirement!

Tuesday, March 07, 2006

JSON as a data binding

In my never ending question for the be-all, end-all cross-language data binding story, I've been thinking lately about JSON.

First, consider that SDO is an important part of IBM's SOA story; it's a or the story for sending data via SCA. Let's compare SDO and JSON, in terms of the Java interfaces.

SDO's DataObject interface looks something like this (see page 23 in the referenced PDF file). Actually, this is just a bit of it.

public interface DataObject extends Serializable { ... boolean getBoolean(String path); byte getByte(String path); char getChar(String path); double getDouble(String path); float getFloat(String path); int getInt(String path); ... }

Now let's compare to JSON's Java interface, and again, just a bit of it.

class JSONObject { java.lang.Object get(java.lang.String key) boolean getBoolean(java.lang.String key) double getDouble(java.lang.String key) int getInt(java.lang.String key) JSONArray getJSONArray(java.lang.String key) JSONObject getJSONObject(java.lang.String key) long getLong(java.lang.String key) java.lang.String getString(java.lang.String key) ... }

Look familiar? Now, sure, SDO has a lot more 'stuff' in it than JSONObject, like change tracking, but, really, I'm not interested in that stuff anyway. In any case, if SDO is good, and JSON smells like SDO, I guess it must be kinda good also.

Next, if I had to implement just one type of 'object' serialization in a server, obvious choices are XML and JSON. JSON is trivial for JavaScript code to eat, and any other language will require some library, but there are plenty available (scroll to the bottom), for free, as long as you don't use them for evil. With XML, everyone needs a library. Not so much of a problem that you need some extra library, because everyone has XML parsers in their language environment, but it's more code you have to write to get the data. If AJAXy web apps are a core piece of what you're doing, JSON may be what you want to make your client-side app code to be a little snappier.

Lastly, one of the things I always think about with data-to-xml bindings is whether fields/properties/etc should be rendered as attributes or child elements. Sometimes, you have no choice; if the field is 'complex', you will likely have to render as a child element. With a string-valued field, you got a tough choice. If the value is small, it feels better usually as an attribute; if it's longer, it feels better as a subelement.

None of this is an issue with JSON. Blissfully choice-challenged.

Sure, there's gotchas with JSON, like the fact that it really just models structs, lists, primitive types. Specifically, it has no way of handling classes. This is an issue when you want to serialize some data in JavaScript, and send it to a typed language, and would like to have that data turned into typed objects; instead of something like SDO's DataObject or JSON's JSONObject. No one wants to deal with that crap. The obvious sort of thing to do is have a magic field in your struct, named maybe "__type__" or something, that provided an indication of the class. This would of course be a pain to have to add manually in the JavaScript object, but if you could provide thin wrappers in JavaScript to poof objects like this up ....

So, I'm thinking it would be interesting to see what a JSON data binding story would look like. On the Java end, I'd want to deal with EMF objects, so the idea would be to serialize EMF objects using it's metadata, and when JSON is deserialized, somehow it gets turned into EMF objects. On the JavaScript end, code that generates these objects would be done with some kind of thin wrapper to add the magic field.

Eclipse Monkey

Ward and Bjorn have put out an interesting plugin for Eclipse called Eclipse Monkey. I bugged Ward after he joined Eclipse to please do something about the dearth of scriptability in Eclipse. This seems like the start of something interesting, but at the moment feels a bit too much like a toy.

It doesn't help that I have almost no experience in writing Eclipse UI plugins. Even the stuff the Find_System_Prints.em is doing is a bit over my head; in terms of what the 'doms' are doing, anyway.

Sunday, March 05, 2006

Hanging Rock

Me and the boys went to Hanging Rock State Park today. Photoset available here. Great weather; about 60°, not too windy, a few clouds in the sky. Also, pretty much empty in terms of other visitors, and no leaves on the trees so you could see more.

Man, I was exhausted by the time we made it to the top. The kids seemed less so. I guess I really am getting old.