Using server-side objects with XML-RPC
XML-RPC is a very handy little standard. It's straightforward, lightweight, and implementations exist for pretty much every language out there.
One thing I've found a bit lacking with it however is that it's kind of a pain to deal with objects. The standard itself supports some very basic types like strings, integers, arrays, and structures. But there's no way of handling more complicated types. A project I've been working on involves manipulating server-side objects over a network connection, so I figured that XML-RPC would be a good place to start.
I believe I've come up with a good way of allowing clients to build proxies for server side objects, while still being compatible with regular XML-RPC implementations.
I've been experimenting a little bit with an XML-RPC server written in Python, and a JavaScript client (using jsolait). I considered adding a new type of parameter (<object>?), but decided against it since it would break older implementations. Instead, the client and server agree to a few conventions:
- A two-tuple whose first element begins with "types." should be interpreted as a reference to an object on the server, where the first element specifies the type of the object, and the second is a unique identifier for that object.
- The server exposes object methods as functions with names of the format "typeMethods.typeName.methodName".
class MyClass:
def doSomething(self, x, y):
pass
def makeObj():
return MyClass()
would be exposed as these XML-RPC functions:
makeObj() /* returns an object reference: ("types.MyClass", objectId) */
typeMethods.MyClass.doSomething(objectRef, x, y) /* objectRef should be ("types.MyClass", objectId) */
When the client sees a two-tuple of the form ("types.MyClass", objectId), it can create a new object along the lines of:
var o = {
"objectId" = objectId,
"typeName" = "types.MyClass",
"doSomething" = function(x,y) {
typeMethods.MyClass.doSomething([this.typeName, this.objectId], x, y);
}}
(JavaScript isn't my strong suit, so I appologize if this isn't exactly right. Hopefully the intent is clear!)
So now you've got a first-class object in your client, with methods that behave just like you would expect! You can now write:
o.doSomething(x,y);
instead of something along the lines of:
serverproxy.MyClass_doSomething(objectId, x, y);
Using the system.listMethods() function to get a list of all methods supported by the server enables you to bind all of a type's methods to an object.
Generating objectId's is application specific, so I won't go into that here. I would like to see a generic way for a user to extend Python's SimpleXMLRPCServer to marshall and unmarshall new data types. The pickle methods (__getstate__, __setstate__) seem promising, but those are intended to serialize the entire representation of an object, not simply a reference to the object.
Comments