JournURL powered

Big Damn Heroes (Tech)


Blog Info

Navigation

<< April 2003 >>
S M T W T F S
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30      

Recent Entries

Alternative Formats

Search

April 18, 2003

Coldfusion MX XML-RPC Component

I've decided to release this little component to the world for two reasons:

  1. There is a scary dearth of CF-related XML-RPC info out there. Aside from a CF5 custom tag that relied on a special installation of MSXML (I never managed to get it working, personally), there have been no tools available. And aside from a Java-centric couple articles in CFDJ, no one is talking about it. The Flash community is way ahead of us on this one, and we need to catch up.
  2. I searched my ass off, looking for guidance on kick-starting XML-RPC support in CFMX. I found nothing but obscure bugs and "I have no idea" responses. With any luck, the next person down the line won't have to spend as much time scratching her head.

DESCRIPTION:

The XML-RPC CFC (Coldfusion Component) streamlines the conversion of XML-RPC packages to and from CFML data structures. It is to XML-RPC payloads as CFWDDX is to WDDX packets. You don't need to know anything about CFMX's XML parsing abilities to use it, either.

REQUIREMENTS:

A Coldfusion MX server running Updater 3+. (Previous CFMX releases had a GetHttpRequestData() bug that kept you from getting at the raw request info you need for XML-RPC.)

DOWNLOAD:

xmlrpc.zip (2,146 bytes)

EXAMPLES:

<cfinvoke component="pathtopackage.xmlrpc" 
   method="XMLRPC2CFML"
   returnvariable="rpcCall"
   data="#GetHttpRequestData().content#">

This will take any incoming XML-RPC packet and convert it into a CFML struct with two members:

  • rpcCall.method (The name of the XML-RPC method that is being called.)
  • rpcCall.params (An array of params containing input data. Per the XML-RPC spec, any of these params may contain complex data types like nested arrays and structs.)

<cfinvoke component="pathtopackage.xmlrpc" 
    method="CFML2XMLRPC"
    returnvariable="rpcCall"
    data="#myArray#"
    type="responsefault">

This is the complimentary opposite of the first method. It takes a CFML array and converts it into an XML-RPC package that you can subsequently send to another client or server. The contents of the array should vary depending upon the value of the type attribute.

(NOTE: Due to CFML's loosely-typed variables, you may run into problems when serializing data for a web service or client that is expecting specific types. See below for details.)

  • type="call"
    You'll use this type when your app is acting as a client of an external web service.
    • myArray[1] should be a string containing the name of the requested XML-RPC method.
    • myArray[2] and beyond can contain data of the types defined in the spec. Each of these array elements will be transformed into top level params in the resulting package.
  • type="response"
    You'll use this type when your app is returning data to a client in response to a method call.
    • myArray[1] should be the only element in the array. It can contain data of the types defined in the spec.
  • type="responsefault"
    You'll use this type when your app is reporting an error to a client.
    • myArray[1] should be an integer representing an error code.
    • myArray[2] should be a string that describes the error.

DATATYPE ISSUES:

CFML's variables are loosely typed, as you're no doubt aware. XML-RPC expects narrowly defined types in its input and output. This creates a problem.

For example, the number 324 is just a numeric variable. It could be a floating point, it could be an integer. Hey, it could be a string in many cases. I went through about a dozen iterations of the private serialize() method, trying to sort out all the possible priorities and the problems they created. In the end, I gave up and cheated. Here's how it works:

  • An array is always interpreted as an <array>.
  • A struct is always interpreted as a <struct>.

So far so good, right?

  • If a variable passes an isNumeric() test, it is an XML-RPC <double> value. It could really be an <int> or a <boolean> or a <string>, but by default, it's a <double>.
  • To force your variable to map to a different element, treat the contents of your variable as a string and prepend the name of the desired element and a dollar sign ($) like so:
    • <cfset myvar = "0">
      <cfset myvar = "$boolean" & myvar>
    • <cfset myvar = 324>
      <cfset myvar = "$i4" & myvar>
    • <cfset myvar = "435644543.09">
      <cfset myvar = "$string" & myvar>
  • If a variable does not pass an isNumeric() test but does pass an isDate() test, it is an XML-RPC <dateTime.iso8601> value. Even if you meant for it to be a <string>, by default, it's a date.
  • To force the variable to map to a <string>, follow the same procedure set out above... prepend "$string" to the contents of your variable.

Yeah, I know. It's ugly. If you come up with something better, send it to me.

NOTES:

  • To help with your first Adventures in XML-RPC, be sure to read the spec, and test your server against an XML-RPC debugger.

04-18-2003 02:52:21AM - Permalink - Post Reply - Read Comments [18] category: Staff
related topics:

return to index