Both of these proposals sound like improvements to me.
I'll point out one consideration that I've had to deal with in Dispatch. The Engine data structures are such that it can be used in a multi-threaded application as long as no two threads are handling the same connection at the same time. By connection, I mean the connection and any sessions, links, and deliveries associated with that connection.
You might want to consider making Collectors specific to connections, so a thread servicing the events in the collector will not touch something that's being handled concurrently by another thread.
-Ted On 01/15/2014 01:35 PM, Rafael Schloming wrote:
Hi Everyone, In a recent thread I alluded to some improvements I have in mind for the engine API and promised a separate post on the topic, so here it is. There are two areas where I'm interested in extending the API. These extensions are strictly speaking independent of each other, but at the same time somewhat complimentary in their utility. The first area would be adding a formal Container class to the engine API. If you are familiar with the AMQP specification then you might have noticed that while the engine API models connections, sessions, and links pretty faithfully to how they are defined in the specification, one notable difference is that the engine API doesn't explicitly model the concept of an AMQP Container. I believe adding such a class to the engine API would allow us to refactor some of the more generally useful stuff that Messenger does into the engine proper, while leaving the less desirable stuff (such as blocking behaviour and hard coded driver) in messenger proper. The second area is providing an event oriented interface into the engine. One of the original ideas behind the engine design is that you don't need event callbacks because the engine itself is simply a state machine, and changes in its state are only ever triggered by calling into the engine API. This means that whenever you make such a call you can simply query to see if anything relevant has changed. While this is strictly speaking true, the whole "query to see what has changed part" is responsible for a fair amount of biolerplate code in using the engine and makes for a steeper learning curve than is desirable. So the idea behind an event oriented interface is to provide a uniform way of discovering what has changed that has a strong analog to the event callback systems most people are used to, but at the same time doesn't go quite so far as to use callbacks. The details of this event oriented interface are somewhat TBD, but my thinking right now on this is to introduce a Collector object that can be registered with an arbitrary number of Containers and/or Connections. The Collector will work in concert with an Event class. The Event class will contain optional references to at most one of each of the following: Container, Connection, Session, Link, Delivery. The event class will also have type, i.e. an enum field indicating what of interest may have occurred. When something of interest happens to a Container, Connection, Session, Link, or Delivery, the library will check to see if there is a Collector registered, and if so create/initialize an Event that points to the relevant engine objects and indicates the appropriate type. Note that no callback occurs here, the Collector just holds the event until the application comes looking for it. The Collector of course has an API for accessing and consuming any events. There are a couple of important principles to note. As stated above there are no callbacks in this interface, this makes it easy to swig into other languages, however it should be only a few lines of code to write a dispatch loop on top of the swigged version of this API, i.e.: for event in collector: dispatch(event) Another important point is that Events are simple transient value objects. They don't carry any significant state in and of themselves, rather they are simply pointers to part of the existing engine state machine that may be of interest. The protocol state is still entirely encapsulated in the engine objects proper, not in the Events. It's also worth noting that I believe both of these extensions are purely additive, i.e. would not require changing any existing API, simply adding new API. Hopefully this type of event oriented interface will provide something that people will have a bit of an easier time digesting/using, but even so, I think it also provides some interesting avenues of future exploration. I believe it would be possible to define a concept of interceptors/filter/whatever that could be configured into a Collector. We could use this to provide reusable/preconfigured behaviours, e.g. if you wanted to use the engine API but didn't want to have to worry about credit, you could install an interceptor that would handle all the credit events for you. Ultimately when combining this interface with the Container concept and introducing Container level events, I believe we could even provide reusable chunks of logic that could handle all of the connection/session/link establishment stuff and thereby provide a single integrated API that would offer the full range of trade-offs between Messenger's simplicity and engine's flexibility. I'd like to flesh this idea out a bit more befire diving in. As a first step I'm working on documenting the existing proton design more thoroughly. You can see what I have so far here, although it is very much in progress still: https://cwiki.apache.org/confluence/display/qpid/Proton+Architecture Once the above document is more complete I will produce a version of the UML that describes in more detail what I have outlined above as a delta to the existing design. --Rafael