Hi, I have tried putting a case forward for three things.

1. Methods as classes, rather than exposed arguments.

Reason: Methods created by factories, allowing multi-version support
(although Raphael points out that if the args change significantly then the
protocol is changing too much between versions, so has gone for a different
solution to the multi-version issue). Allows one implementation of methods
as byte buffers, another as java fields, for in-vm transport. Keeps open
possibility of native implementation. Allows pass-through processing, where
method is never decoded or only partially decoded. Also, it might be
possible to do faster serialization/deserialization, using a JVM tweaked at
the byte code level. I believe that Terracotta (http://terracottatech.com/)
gets up to such tricks. There is also an out-of-date project,
http://www.eecs.harvard.edu/~mdw/proj/old/jaguar/, that does this sort of
thing too, no idea but maybe the Terracotta folks got some ideas from there.

2. Full mapping of the protocol 1:1 onto the API.

I agree that onMessage is the most frequently handled incoming method on the
client side, but there is the rest of the protocol to consider too. The API
just isn't low-level if it does not expose everything.

3. Use of the inverse symmetry of the API so that the outgoing interface
that the client calls, is identical to the incoming interface that the
broker routing layer implements.

Comm layer can be completely bypassed, and a client can be directly welded
onto the broker.

I think I should add a fourth to this list:

4. Be language neutral, that is a suitable API for implementing in any of
our target languages.

Can assume target language is OO? Not sure I'd like to invent an API that
equally well maps onto an OO as well as a functional language ;).

To these ends, I have been playing around with the Stub that Raphael
originally posted to this list. I am slowly getting an API into shape, on my
laptop on the way to and from work on the train, but haven't really the time
to dedicate to completing it yet.

Here is a rough outline:

Everything in the API is an interface first, the comm layer implements it. I
like interfaces, because you can have multiple implementations. There is
also a toy broker that implements some of the interfaces too, allowing
direct connection of the client onto an in-vm broker.

Every 'class' in the protocol has two interfaces in the API. One for the
outgoing calls that the client may make to the broker, one for the calls the
broker may make to the client.

Every 'method' in the protocol has an interface.

All the outgoing 'classes' are pulled together into a single interface, and
all the incoming 'classes' are pulled together into a single interface that
extends them all. The reason for splitting down on per-'class' basis, is in
case someone wants to implement a delegate for just one 'class', rather than
having to implement all methods. The were probably also be no-op abstract
implementations, that can be extended to write delegates that handle just
one 'method' event out of a 'class'.

Methods are created by a method factory.

Methods can be called in the context of a connection, or a session. The
initial connection creation and session creation are performed by calling
their 'open' methods.

The comm layer implements both the incoming and outgoing 'classes', you have
to ask the factory for the flavour you want depending on the context. For
example the interface for the client to call the broker is called
'ProtocolBroker' (extends ClassSessionBroker, ClassMessageBroker, etc), and
the one for the broker to call the client is 'ProtocolClient'.(extends
ClassSessionClient, ClassMessageClient, etc).

The factory allows you to register delegates, with the comm layer. When the
comm layer receives incoming frames, it delegates the decoded method calls
onto the delegate (I think just one delegate for the moment, rather than an
interceptor pattern style chain, not sure, will probably have to do some
kind of chain eventually, xwork/webwork may provide some inspiration for
this).

The 'toy' broker I have sketched out, implements ProtocolBroker. It also
provides a protocol factory, this factory will throw an exception if you ask
it to create a ProtocolClient, but it will give you a ProtocolBroker.

So to write a client against the comm layer, ask its ProtocoFactory
implementation for a ProtocolBroker. To write a client directly against the
broker routing engine, ask its ProtocolFactory implementation for a
ProtocolBroker. This is point 3 above, about the inverse symmetry of the
interfaces.

Some methods in the protocol require a response, but all are asynchronous.
For this I am providing a pair of conversation interfaces, with wait for
methods. So for example to open and attach a session, I do:

ProtocolFactory factory = ...
ProtocolBroker invoker = ...
ConnectionContext connection = ...
ProtoclClient delegate = factory.defaultClientDelegate();

MethodOpenSession = factory.getMethodFactory().createOpenSession(...);

Conversation conversation = factory.createConversation(invoker, delegate);
SessionContext session = conversation.openSession(connection, openSession);
conversation.waitForSessionAttached();

Sorry, for being a bit light on the details. I don't have it in a state I am
ready to release yet, also it is stuck on my laptop at the moment, as I
can't connect my personal lap-top to the net at work, and my home server is
down at the moment due to moving house. I will post it to the list, once it
feels right to me. I have very successfully retro-fitted Raphael's stub onto
my API, shifting things around a bit, but keeping essentially the same code.
I just wanted to post to try and keep my ideas alive, as I think they are
worthwhile, and I don't feel that the API at,
http://cwiki.apache.org/confluence/display/qpid/Message+API+Design,
satisfies any of my three criteria.

The generated API for the comm layer does look to me like a good low-level
API. One thing I would prefer to see though, is it implementing a set of
interfaces. Also, for that set of interfaces not to use generics, primarily
for backward support for java 1.4, or for non-parametric-polymorphic
language implementation.

I do agree with the comment that Raphael made on the meeting last week, that
the push API for large messages, is better than a pull one. Simply because
it will be more natural to write a pull utility on top of a push API, and a
push API makes less assumptions about a threading model. However, the API
at: http://cwiki.apache.org/confluence/display/qpid/Message+API+Design,
looks very similar to me, to what is already available in JMS as
javax.jms.StreamMessage?


On 15/08/07, Rajith Attapattu <[EMAIL PROTECTED]> wrote:
>
> folks,
>
> I have captured the design notes for the new client API at
> http://cwiki.apache.org/confluence/display/qpid/Message+API+Design
>
> This is to give a heads up on the direction we are talking.
> I believe this is extremely close to the ideas we agreed on the dev list.
>
> Regards,
>
> Rajith
>

Reply via email to