Yes, but a method called invoke doesn't make for a very good API. It is good
to use method names that give some indication as to the purpose of the call.

As already mentioned passing a MethodX structure to a named method on an
invoker has the advantage of keeping the method structure implementation
opaque, keeping some performance options open.

For example, I know of one customer who wants to use two brokers, with a
back-to-back client in between them, that forwards the messages from one to
the other. I am not 100% sure of his motivation for this design, something
to do with firewalls/security, I'm not sure. Anyway, the point is, that he
could take advantage of the low-level API to write this back to back client,
directly applying the incoming MessageTransfer as an outgoing
MessageTransfer between a MessageInvoker and MessageDelagete. Perhaps all he
would need to decode and change might be the routing key.

I also thought of another reason why using opaque structures rather than
exposed method arguments might be a good thing. If we were to implement some
sort of event driven architecture in the broker, the Method structure
themselves would be the events handled by the routing stage. (ActiveMQ is
using a SEDA design to good effect).

Example. The commlayer handles incoming Frame events, and produces Method
events. The routing layer handles incoming Method events and produces
outgoing Method events. The commlayer handles incoming Method events and
produces outgoing Frame events.

Frame -> Comm layer stage -> Method -> Routing stage -> Method -> Comm layer
stage -> Frame

You can make the events, Frame and Method, implement an interface Sizeof
(behind the scenes, no need to expose in the public API).

public interface Sizeable
{
    /**
     * Calculates the size of this object in bytes.
     *
     * @return The size of this object in bytes.
     */
    long sizeof();
}

Then each stage can be made to exert back pressure under excessive numbers
of queued events, or excessive amount of queued data, providing an excellent
way to protect against overload.

Rajith, no need to apologize, I'm just trying to provide constructive
criticism and the feedback that you asked for.

I think sharing and discussing our ideas is going to lead to a better
design. I also think that the design of an API is critical, and extremely
important to get right. I would much rather work on a piece of software with
a great API and poor implementation, than one with a bad API and reasonable
implementation, because I know that the former can always be improved,
wheras the latter will always be fighting against its limitations. As I say,
you rarely get more than one chance to design an API, and a good one does
not come easily.

Also, we've been much too busy with M2 to engage fully with this.

Rupert

On 31/07/07, Rafael Schloming <[EMAIL PROTECTED]> wrote:
>
> Rupert Smith wrote:
> > I think this is heading in the right direction ;)
> >
> > I'm not sure about the need for a MessageSender (especially not one
> bound to
> > a queue!). At this level it would seem quite suitable just to call
> > methodTransfer.
> >
> > Also worth noting is the reverse symmetry of the Invoker/Delegate
> > interfaces. Delegate is the incoming interface for the client, but the
> > outgoing one for the broker. Might it be possible to use the same
> interfaces
> > in both, albeit from opposite perspectives?
> >
> > I can understand why the Invoker/Delegate include all methods in all
> > 'classes' in the protocol. It makes it easier to write the stub, and
> > provides version specific implementations that only respond to the
> methods
> > relevant to a version.
> >
> > We can work out what is the best way to present the methods as an API,
> all
> > in one big class/interface seems too unweildy. So I think you are doing
> the
> > right thing, filtering to expose the methods by 'class'.
> >
> > One big difference between the outgoing and incoming interfaces, is the
> way
> > method arguments are presented.
> >
> > In ClientSession:
> >     public void messageBody(byte[] src) throws QpidException
> >
> > In SessionDelegate:
> >     public void queueBind(Session session, QueueBind struct) {}
> >
> > The arguments are exposed directly in the ClientSession one, but as
> opaque
> > structs in the incoming one. For the reasons I gave earlier, about the
> > possibility of wrapping direct buffers, and exposing method structs as
> > opaque interfaces on top of them, might it be an idea to make the
> outgoing
> > interface take strucs as arguments instead?
> >
> > A quick example, supposing I receive a message as a MessageTransfer
> struc. I
> > could send it back out again as a MessageTransfer struc. If the struc is
> > really a wrapper on a byte buffer, no or minimal decoding/recoding could
> be
> > done on the buffer.
> >
> > This is just an idea, it makes the API somewhat less wieldy, by
> requiring
> > the use of a factory to create strucs before calling methods. But more
> > flexible as the same factory interface can be used, that provides
> versioned
> > strucs.
>
> I think we actually have both options right now. The methods on the
> invoker are essentially just syntactic sugar that provides a convenient
> means to construct an object, fill it out, and send it on it's way. Each
> method on the invoker follows this template:
>
> public void <methodName>(<methodArgs>)
> {
>      invoke(getFactory().newMethodName(<methodArgs>));
> }
>
> Where invoke is just an abstract method:
>
>    abstract void invoke(Method method);
>
> If I happened to have an already constructed <MethodName> object that I,
> e.g. read in off the wire, I could just pass it directly into the
> invoke(...) method, and we could of course make the generated
> implementations of each <MethodName> object be smart enough to only
> decode/reencode on demand.
>
> --Rafael
>

Reply via email to