related to https://jira.jboss.org/jira/browse/HORNETQ-129.
The idea is to support stomp natively so that any stomp clients can talk to HornetQ server directly.
(it is already possible to use StompConnect with HornetQ 2.0.0 though).
Currently HornetQ support a single protocol: let's call it HornetQ core.
Stomp would be a 2nd supported protocol.
I'm prototyping Stomp support to see what we need to refactor to be able to plug another protocol
without disrupting the server code.
First thing is that the protocol supported must be usable regardless of the transport.
I.e, both core and stomp protocol should work using Netty and in-vm transports.
We need to add a "protocol" configuration to the TransportConfiguration.
Depending on this protocol we need to:
- know how to identify a protocol frame (e.g. with core, we use a content-size delimiter while
stomp requires a null-ending delimiter)
- know how to transform a buffer from the transport to a corresponding frame
(hornetq code will create Packets, stomp will create StompFrame)
Once we have these objects, we must them call the server resources to handle the commands.
Then, we must (optionally) reply to the client. This again depends on the protocol, we need to add an encoder
which will take a packet/stomp frame and encode it in a HornetQ buffer which is sent on the transport.
Let's take a simple example to illustrate this: a session creation.
Let's say that the servers has 2 acceptors: 1 for core protocol and 1 for stomp protocol.
- a Core client sends a CreateSessionMessage packet
- the "core" acceptor receives the message
- it uses a content-size delimiter to create a HornetQBuffer corresponding to the packet
- it uses a PacketDecoder to create the packet from the buffer
- it passes the packet to the HornetQServerPacketHandler which creates the session
- the HornetQServerPacketHandler then send a CreateSessionResponseMessage on the channel
- the CreateSessionResponseMessage encodes itself in a HornetQBuffer which is sent on the transport
- a Stomp client sends a CONNECT command
- the "stomp" acceptor receives the message
- it uses a null-ended delimiter to create a HornetQBuffer corresponding to the packet
- it uses a StompMarshaller to create a stomp frame from the buffer
- it passes the packet to a HornetQServerFrameHandler which creates the session
- the HornetQServerFrameHandler then sends a CONNECTED frame on the channel
- the CONNECTED frame encodes itself in a HornetQBuffer which is sent to the transport
Currently our code is not modular enough to run this scenario:
- we need to be able to configure encoder/decoded/delimiter for a given protocol on the acceptor
- we need to set a frame/packet handler depending on the protocol too
Our main server resources (HornetQServer, ServerSession) sends responses bound to the core protocol directly.
We must change that so that the stomp protocol can chose what must be replied to the client (using Stomp frames).
We can be able to use generics to achieve this modularity. e.g Core connection/channels/handler will be using <Packet>
while Stomp connection/channel/handler will use <StompFrame> (fiy, this is similar to the prototype I did some time ago for AMQP integration).
The main point is that we should have a single implementation for the transport layer and only needs few classes per protocols:
- codec & delimiter (to translate buffers to protocol POJOS)
- handler (to call server resources based on the protocol POJOS)
However, there are 2 questions that I need to think about more: features associated to connections and client/server interactions.
For example, Stomp does not have heartbeat. Currently in my proto, the Stomp connections is rapidly killed by the server because the client did not send a ping. I must disable ping check for stomp connections to comply to the protocol.
I also wonder about client/server interaction, e.g. credits. Stomp protocol has no notion of protocol. I wonder if our server resources are able to work
with clients which does not offer these interaction (credits, windows, anything else?).
I'll commit my prototype in a branch so we can look at the code and agree on the refactoring to apply to support other protocols