> If we decide to go ahead and make an XmlRpcClient interface,
> we either have to decide to use some NonImplementedException
> framework for the features of the interface that
> XmlRpcClientLiteImpl does not implement, or we need to
> use an abstract class with the bare minimum for the root
> interface and inherit XmlRpcClientWithMoreHttpFeatures from it.
>
> Are there other features XmlRpcClient provides now that
> XmlRpcClientLite  does not, like multithreading?
> If so, these should  be addressed as well.

I've been looking into this myself. I've finished integrating
and testing the pre 1.2 release of Apache XML-RPC with parts of
our own software (we use a home-grown HTTP implementation for
various reasons). It works nicely with our C client. I now need
to write a Java client to talk to our Java server and a C server.
But, I need to be able to do XML-RPC as well as other HTTP PUT
and GET request on the same connection to the server (ie. the
same socket).

So, I would like to rearrange the client classes so that XML-RPC
encoding and decoding was separated from the HTTP send and
receive. This should simplify client implementation for the
three clients: Lite, Current, and Jakarta Commons.

As I see it, there are the steps involved in making an XML-RPC
request, in the case of a persistent HTTP connection:

1. Create and configure the default options for a HTTP connection.
2. Make the socket connection to the server.

3. Prepare an XML-RPC request (an actual ASCII byte stream)
4. Set any per-request HTTP options. Send the HTTP request
   (POST), headers and terminating newline.
5. Send the XML-RPC request byte stream.
6. Receive the HTTP response headers.
7. Receive the XML-RPC response.
8. Parse the XML-RPC response.
9. If the XML-RPC succeded: return the received object,
   otherwise: throw the received exception.

Further requests on a persistent HTTP connection start at 3.

I would like to extract code to perform step 3 into:

XmlRpcClientRequestProcessor
  void encodeRequest(XmlRpcRequest req, String encoding, OutputStream out)
  throws XmlRpcClientException
  byte [] encodeRequestBytes(XmlRpcRequest req, String encoding)
  throws XmlRpcClientException

And step 7 and 8 into:

XmlRpcClientResponseProcessor (extends XmlRpc)
  // Step 7: Decode a response, return an Object or an Exception
  Object decodeResponse(InputStream in, int contentLength)
  throws XmlRpcClientException

  // Step 7 & 8: Decode a response. If the response is an exception,
  // throw it as an XmlRpcException, otherwise return it.
  Object handleResponse(InputStream in, int contentLength)
  throws XmlRpcException, XmlRpcClientException

also, {decode|handle}RequestBytes(byte []) that take a byte[]
instead of an InputStream.

Then, based on a similar refactoring to the one performed on the
server, have an abstract XmlRpcClient that manages a thread pool.
The main entry points are the execute and executeAsync methods:

Object execute(XmlRpcRequest request, XmlRpcClientContext context)
throws XmlRpcClientContext, XmlRpcException

this method gets a worker (or creates one), then calls the worker's
execute method. It then returns the result in the current thread.

void executeAsync(XmlRpcRequest request, XmlRpcClientContext context) 
throws XmlRpcClientContext, XmlRpcException
this returns immediately after enqueuing the request. The response
will be returned in a separate thread via the XmlRpcClientContext
(see later).

The XmlRpcClient also has an abstract factory method:

  XmlRpcClientWorker createWorker().

that returns an appropriately configured XmlRpcClientWorker.

XmlRpcClientWorker has as its major method:

Object execute(XmlRpcRequest request, XmlRpcClientContext context)
throws XmlRpcClientException, XmlRpcException

This method is responsible for doing steps 3-8 (with the help of
the XmlRpcClient*Processor classes). The context object can be
used by the worker in a multitude of ways to handle connection
persistence, multiplexing, HTTP headers, encryption, drug
dealing and the like.

The XmlRpcClientContext object has at least the following methods:
?  getHTTPHeaders()
   returns the HTTP headers for this request.
   This would probably return String [], maybe Vector?

String getUsername()
String getPassword()
   - possibly, probably just part of getHTTPHeaders

AsyncCallback getCallback()
   returns the callback to respond to - null means discard the
   response. This is only called after the response has been
   received, but may be called before or after it has been
   decoded.

Workers are free to cast the XmlRpcContext to some other class
or interface that may define extra methods.

The XmlRpcClientException is an exception to indicate that something
went wrong in the processing of the XML-RPC as part of client
processing. eg. an invalid encoding was specified, the specified
host could not be contacted, etc. It has a Throwable getCause()
method in the Java 1.4 style, with appropriate constructors.

I am naturally willing to code this all up, test it and put it
as a patch in bugzilla for general consumption. I'm 90% sure it
can be done without too much breakage from the 1.1 API. I have
time available to work on this now and in the near future. Let me
know your opinions ;)

Andrew.




Reply via email to