== The Cocoa XML-RPC Framework

The  Cocoa  XML-RPC  Framework is a lightweight, simple, and easy-to-use XML-RPC
client  written  in Objective-C for use in OS X applications. An XML-RPC request
can  be  sent  asynchronously  or  synchronously, depending on the intentions of
its use.

== Requirements

The  Cocoa  XML-RPC  Framework  has  been  built, and designed, for OS X 10.4 or
later.  The  framework  relies  on  NSURLConnection  and  NSURLRequest  for HTTP
transport, and NSXMLDocument for parsing XML-RPC responses.

== Usage

The  following  examples of the Cocoa XML-RPC Framework assume that the included
XML-RPC test server are running. The test server can be found under:

    XMLRPC\Tools\xmlrpc-server

The  XML-RPC  test  server  is  written  in Java and utilizes the Apache XML-RPC
server  library.  To  start  the  server simply call Ant from the same directory
where the build.xml file is located:

    ant <target>

The  target  is  optional,  omitting  this  argument  will  execute  the default
target (the default target is "run"). The following targets are available:

  - compile
  - jar
  - run
  - clean

More information on the XML-RPC test server can be found below.

= Asynchronous

Making  an  asynchronous XML-RPC request is probably the best way to communicate
with  an  XML-RPC server. After creating an XMLRPCConnection the XML-RPC request
is  sent  to  the  XML-RPC  server in the background. This allows the requesting
application to continue performing other functions.

Sending an asynchronous XML-RPC request is simple:

- (void)sendRequest {
    NSURL *URL = [NSURL URLWithString: @"http://127.0.0.1/"];
    XMLRPCRequest *request = [[XMLRPCRequest alloc] initWithHost: URL];

    [request setMethod: @"Echo.echo" withParameter: @"Hello World!"];
    [request setUserAgent: @"XML-RPC Example"];
	
    XMLRPCConnection *connection = [[XMLRPCConnection alloc]
        initWithXMLRPCRequest: request delegate: self];

    if (connection == nil) {
        NSLog(@"Connection failed.");
    }
}

It  is  important to understand that the caller is responsible for releasing the
connection  and  response  objects  at  the  end  of the connection response and
connection  failure  delegate  methods. Do not attempt to release the connection
object anywhere but within these two delegate methods.

- (void)connection: (XMLRPCConnection *)connection didReceiveResponse:
        (XMLRPCResponse *)response forMethod: (NSString *)method {
    if (response != nil) {
        if ([response isFault]) {
            NSLog(@"Fault code: %@", [response faultCode]);
        } else {
            NSLog(@"Response object: %@", [response responseObject]);
        }

        NSLog(@"Response source: %@", [response responseSourceXML]);
    } else {
        NSLog(@"Unable to parse response.");
    }

    [response release];
    [connection release];
}

= Synchronous

Synchronous  XML-RPC requests may be suitable in some situations. Unlike sending
an asynchronous request, a synchronous request is made in the foreground causing
the calling application to await an XML-RPC response.

- (void)sendRequest {
    NSURL *URL = [NSURL URLWithString: @"http://127.0.0.1/"];
    XMLRPCRequest *request = [[[XMLRPCRequest alloc] initWithHost: URL]];

    [request setMethod: @"Echo.echo" setParameter: @"Hello World!"];
    [request setUserAgent: @"XML-RPC Example"];

    XMLRPCResponse *response = [XMLRPCConnection
        sendSynchronousXMLRPCRequest: request];

    if (response != nil) {
        if ([response isFault]) {
            NSLog(@"Fault: %@", [response fault]);
        } else {
            NSLog(@"Response object: %@", [response responseObject]);
        }

        NSLog(@"Response source: %@", [response responseSourceXML]);
    } else {
        NSLog(@"Unable to parse response.");
    }

    [request release];
    [response release];
}

A response will always return nil upon creation if it is unable to parse the XML
data.  However,  in the case of a synchronous request, a nil response can either
mean  the  response  could  not  be parsed, or the connection failed to send the
request.

An  asynchronous connection will return nil if it fails to send the request. The
response   passed   to   the  connection:didReceiveResponse:forMethod:  delegate
method  will  be  nil if the response object is unable to parse the XML response
data.

Also  note  that you may have access to the raw XML source to either the request
and/or  response.  Though you may be able to extract the source from the request
at  any  moment  in the object's life, it is always best to get the source after
invoking  the  setMethod:withParameters: or setMethod:withParameter: methods. If
you  ask  for  the  source  too  early,  you won't receive the fully created XML
request source.

== Using the XML-RPC test server

The  XML-RPC  test server is a simple Java application that allows developers to
easily  develop  software with Cocoa XML-RPC Framework. The test server is built
on top of the Apache XML-RPC library.

Using  the  test  server  is easy, simply call Ant from the same location as the
build.xml file:

    ant

The default target is the "run" target, which will compile the Java source code,
build  the  executable JAR file, and run the application. Included with the test
server  is  a server.sh script, this Bash script will launch the test server (if
it has already been built with Ant).

= Creating XML-RPC server handlers

The  XML-RPC  test  server  exposes the methods defined in server handlers. Each
server handler is simply a Java class that is registered with the Apache XML-RPC
library. Here is an example of the Echo handler provided in the distribution:

    public class Echo {
        public String echo(String message) {
            return message;
        }
    }

This  handler simply takes a message provided in the XML-RPC request and returns
it  in  the  XML-RPC  response. To register this handler with the XML-RPC server
simply add it to the propertyHandlerMapping in Server.java:

    import com.divisiblebyzero.xmlrpc.model.handlers.*;

    ...

    try {
        propertyHandlerMapping.addHandler("Echo", Echo.class);

        this.embeddedXmlRpcServer.setHandlerMapping(propertyHandlerMapping);
    } catch (Exception e) {
        this.controlPanel.addLogMessage(e.getMessage());
    }

The handler is now available to any incoming XML-RPC requests.

== What if I find a bug?

The  Cocoa  XML-RPC  Framework has been developed on my free time. Any comments,
questions,  bug  reports and/or suggestions can be sent to eczarny@gmail.com. If
you find this framework useful I would appreciate receiving the necessary credit
where ever due.

== Acknowledgments

The  Base64  encoder/decoder found in NSStringAdditions and NSDataAdditions have
been  adapted  from  code  released  by Dave Winer and Brent Simmons. Dave Winer
wrote  the original Base64 encoding and decoding routines. Brent Simmons adapted
Dave Winer's code for use with Objective-C.

== License

Copyright (c) 2008 Eric Czarny.

The  Cocoa XML-RPC Framework  should  be  accompanied  by  a  LICENSE file, this
file  contains  the license relevant to this distribution. If no LICENSE exists,
please contact Eric Czarny <eczarny@gmail.com>.
