The Open Scripting Architecture is a nice bit of engineering, but it doesn’t make my life easier at the moment. To script an application on OS X, I have to use a language that supports the OSA: AppleScript, Javascript, Perl, Ruby, Python, UserTalk, or (arguably) Cocoa/Java. Objective-C and Java hardly count as “scripting” languages, but I’ll let that slide. The important thing is that I can’t sit down and script an arbitrary application in an arbitrary language, where arbitrary language means the language I want to use today.
If I want to communicate with an application under OS X, I get a limited set of data I can send at the application: Booleans, numbers of various sorts, strings, lists of these types of data, and values (record pairs, or a hash table, roughly). Because most programming languages support all of these types of data, you’d think I could script OS X applications from any language. Wrong!
I want to, though. Time for pictures.

Fig 1: Using the OSA to talk to an Application
I can talk to any application running on OS X using the Open Scripting Architecture (figure 1); this means I just have to use one of the languages that speaks OSA. I don’t want to use one of them, though.

Fig 2: Pushing a language through the OSA to get to an App.
I could “push” my language of choice through the OSA, somehow (figure 2). This seems… tedious. I could do that by adding OSA support directly to my language, by cross-compiling some or all of my chosen language into one that supports the OSA, or in the case of PLT Scheme, I could build on the existing AppleEvents facilities, which I could probably do if I put some more time into it.
Of these, my third solution is best: it leverages existing work, and relies on supported features of my language that I can trust to… well, I can trust to be supported. Unfortunately, any solution that ties me to one language (and, in the case of Scheme, one implementation of the language) doesn’t solve the real problem: I want to script any application from any language.
Next slide, please.

Fig 3: Using XML-RPC for cross-language communication.
I have, in the past, written programs that talk to each-other, even though they are in completely different languages. At IUB, I had a handy set of scripts that processed my research data on 60 machines simultaneously, using a combination of Scheme and Perl. I’ve also had cases where I’ve driven Java programs from Scheme; odd, but it was useful. Drop in a little web-server, an XML-RPC library, and I have cross-language communication.
After my post yesterday regarding OmniGraffle, I had a nice back-and-forth over email with the two members of the OmniGroup about this. We left it off with this solution:

Fig 4: A piece of software that converts XML-RPC calls into OSA events.
I should write an XML-RPC to OSA adapter (figure 4). This way, they don’t have to write any code, and if done right, my “black box” can act as an adapter for any application. This, I must admit, is true. And until I went on a walk into Canterbury this afternoon, I thought it was nothing more than a stopgap for the real solution. I had convinced myself that applications should have support for XML-RPC built in, as opposed/in addition to the OSA.

Fig 5: Using XML-RPC to script Applications
I realized this is wrong. And it is wrong for several reasons.

Fig 6: Problems abound if you push XML-RPC down to the App
–>
- A lack of standards. Every single app will have a different API, and if I want to tell the application to open a file, I have to figure out what RPC endpoint I have to call to make it happen. It could be called openFile, open, fileOpen, or anything else.
- A port number nightmare. If every application has a tiny HTTP server built in, I have no idea what port number they’re all on. And what happens when I have two apps that want the same port? Even if they sort themselves out, my script won’t be able to find the endpoint it’s looking for.
- Incompatibilities. One XML-RPC implementation will support introspection, while another one won’t. One server will give proper HTTP error codes, while another one won’t. Every endpoint will have it’s own quirks, and it will be up to me, as a scripter and application developer, to keep track of all those quirks. That is bad.
So where does this leave me? If I add support for the OSA to My Favorite LanguageTM, then only my language can make use of the new feature: I gain one more OSA-enabled scripting language. If I push it into the application, I end up with lots of problems: dialects, collisions, the works. The benefits are worth solving the problem: any language that handles XML and talks HTTP can drive an app in my proposed regime, and that’s a lot of languages. Being able to script one application on one machine from another machine is another win, which is something I think you can’t do with AppleScript (but I don’t know for sure).
While the black box, as drawn in figure four, seems to be in-between the applications, where I really need to think of it is below.

Fig 6: OSA is a system service
The Open Scripting Architecture is a system-level messaging service. Languages can patch into it to send events to applications. Client applications can register themselves with the service, and listen for messages destined for them. In this way, OSA is providing both an API for communication, as well as brokering communications between the scripter (regardless of language) and the target application.
If I want to have XML-RPC as a scripting interface to applications on OS X, I need to provide an XML-RPC service. It has to eliminate the possibility of port collisions, it has to eliminate my wondering what port any given application is listening on, and it has to guarantee consistency in the transport protocol and APIs as I move from scripting one application to another. OSA already does all of this, so I need to as well.

Fig 7: XML-RPC as a system service
Apple is not going to dump the OSA or AppleScript. I can’t get application developers to support yet another scripting interface—they aren’t going to make their apps “MCJ XML-RPC Service”-aware. So, I have no choice but to build on top of OSA if I’m going to leverage existing technology (OSA), keep track of where apps are (OSA), and interop with as many existing applications as possible (that use the OSA).
I do get a lot of things for free, though. I only need one server, and that server handles mapping all my XML-RPC calls to the appropriate AppleEvents. It can even pull apart target application dictionaries, and provide an introspection interface at the higher level. All of the hard work is done by the middle layer, and the scripter just makes calls against the new service.
I’m not saying anything here that hasn’t really been said already: Dave Winer, in his article Fractional Power HTTP Servers, said the same thing, but he didn’t push it all the way down—and if you don’t, it breaks. Or, at the least, the tedium and inconsistencies I describe plague every scripter everytime they want to script another application.
Punchline
| I’m looking at writing a native OS X service to map XML-RPC calls to their Open Scripting Architecture equivalents. This is well beyond my expertise; I am capable of it, but it will take forever and a day. Pointers, suggestions, and willingness to help would all be appreciated.
Email jadud at acm dot org if you’re interested in taking part, or leave a comment below. |
References
I’m really, completely, 100% treading on well walked ground. This isn’t new.
- The XML-RPC homepage (spec)
- DaveNets on this topic: 1996.06.16, 1997.09.14, 1998.03.28, 1998.07.14, 1998.07.19, 1998.11.17, 1999.01.29, 1999.02.04, 1999.09.20, 2000.10.03, 2000.11.30… oh, you get the picture.
- Tutorials and press related to XML-RPC.
- OmniGraffle, a first-class diagramming tool for OS X.
- Greg Titus, one of the cool people in the OmniGroup who didn’t tell me to zark off. Joel Page, Support Ninja Linebacker, cannot be directly referenced. Both are participants in the referenced, but invisible to you, email exchange.