2 Replies Latest reply on Jan 19, 2010 1:00 PM by Tim Fox

    Stomp native support

    Jeff Mesnil Master

      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.

       

      Core:

      - 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

       

      Stomp

      - 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

        • 1. Re: Stomp native support
          Tim Fox Master

          jmesnil wrote:

           

          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.

           

          Core:

          - 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

           

          Stomp

          - 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

          Like you say, currently the serversession etc deal with packets directly - I think we should remove all references to packets from ServerSessionImpl, HornetQServerImpl, ServerConsumerImpl etc

           

          The packet is really a core concept and not appropriate for STOMP (or AMQP). Instead the server layer (HornetQServerImpl, ServerSessionImpl, ServerConsumerImpl) should be 100% protocol agnostic, and just deal with parameters as typed Java values.

           

          Any client responses should be sent from the protocol specific handler not the server layer. If the server layer needs to send a message (e.g. message delivery) then it needs to call into the protocol specific layer to do this.

           

          Regarding stuff like heartbeats, flow control etc. This isn't a problem - for STOMP we just set ttl appropriately for all stomp connections. And flow control is basicallly set to -1 (no flow control)

          • 2. Re: Stomp native support
            Tim Fox Master

            To take this a step further.

             

            If the ServerSession has a reference to it's packet handler, instead of directly to the Channel, then the packet handler is specific to the protocol.

             

            The packet handler can handle all the responses, we can also add methods to the session handler for example like:

             

            void sendMessage(final Message message, final int deliveryCount);

             

            this can be implemented  by the handler which sends the message in the way appropriate to the protocol.