Version 7

    This page describes the proposed new Remote API to be used by JBoss Messaging

     

    It is planned for JBoss Messaging 2.0 to use MINA as the transport layer between JMS clients and server peers. In order to integrate seamlessly MINA into JBoss Messaging, a new Remote API needs to be introduced.

     

    Tracked by JBMESSAGING-544.

     

    This API is discuted on the design forum

     

    A prototype of this API is available from svn: http://fisheye.jboss.org/browse/Messaging/branches/Branch_JBMESSAGING-544

     

    JBoss Messaging 2.0 uses MINA as its framework to build its protocol to communicate between Messaging clients and servers.

    However, from JBM Core point of view, there is no dependency to MINA. Everything is wrapped by an API.

     

    New remote communication API

     

    The main parts of the API are Packets, PacketHandlers, PacketDispatcher and Client.

     

    A Packet represents a "packet" of information exchanged between a client and a server (in either direction).

    Examples of such packets are: request to create a JBM session, response containing the ID of the created JBM session, the delivery of a Messaging message, the acknowledgement of this message, etc. (New packets will be very similar to the current wireformat defined in org.jboss.jms.wireformat)

     

    The base class of a packet is AbstractPacket.

     

    It contains attributes to route correctly the packet:

     

    public abstract class AbstractPacket
    {
       private long correlationID = NO_CORRELATION_ID;
    
       private String targetID = NO_TARGET_ID;
    
       private String callbackID = NO_CALLBACK_ID;
    
       private PacketType type;
    
       private byte version;
    }
    

     

    • correlationID is used to correlate packets forming a request/response couple (used only by RemoteDispatcher.sendBlocking() method)

    • targetID identifies the PacketHandler on the receiver side which must handle this packet

    • callbackID identifies the PacketHandler on the sender side which must be called back if a packet is expected to be received later as a reply to the sending of this packet (used only by RemoteDispatcher.sendOneWay(AbstractPacket, PacketHandler))

    • version is a mandatory attribute which must be set to determine the protocol version of the sender-side

     

    Packet reception is handled by a PacketHandler:

     

    public interface PacketHandler
    {
       String getID();
    
       void handle(AbstractPacket packet, PacketSender sender);
    }
    

     

    The ID returned by getID() must be unique (at least among the IDs registered into a RemoteDispatcher).

    For simplicity sake, a abstract class AbstractPacketHandler is provided and uses Java 5 UUID class to generate a random UUID.

    An example of a PacketHandler is the connection handler: it handles a request to create a session, create the session and sends a response containing the ID of the newly created session

    Another example is the consumer handler: it handles a client delivery containing a Messaging message, delivers it to the Core consumer and optionnally sends an automatic acknowledgement back.

     

    When handling a packet, the PacketHandler has access to a PacketSender in case it needs to reply (which should be the case only on the server-side).

     

    The PacketDispatcher is responsible to register/unregister & retrieve PacketHandler based on an ID.

     

    public class PacketDispatcher
    {
       public static final PacketDispatcher client = new PacketDispatcher();
       public static final PacketDispatcher server = new PacketDispatcher();
    
       public void register(PacketHandler handler)
       {
          ...
       }
       
       public void unregister(String handlerID);
       {
          ...
       }
    
       public PacketHandler getHandler(String handlerID);
       {
          ...
       }
    

     

    There are 2 singletons of PacketDispatcher: one to register "server-side" PacketHandlers

    and another to register "client-side" PacketHandlers.

     

    An example of object registerd on the client-side is for client delivery. A ClientDeliveryHandler will be registered when a Consumer is created on the client side.

    When the server want to deliver message to this client, it will send client delivery packet with a target ID corresponding to the ClientDeliveryHandler.

     

    This is a design issue: corresponding objects (ClientSessionDelegate & ServerSessionEndpoint have same ID on the server-side and client-side but they must handle different sets of messages.  Using one singleton makes tests fail when everything runs in a single VM

     

    The Client is used to send packets:

     

    public class PacketDispatcher
    {
       public void connect(String host, int port, TransportType transport, boolean useSSL)
       {
          ...
       }
    
       public void disconnect()
       {
          ...
       }
    
       public void sendOneWay(AbstractPacket packet)
       {
          ...
       }
      
       public AbstractPacket sendBlocking(AbstractPacket packet)
       {
          ...
       }  
    }
    

     

    There are 2 different ways to exchange packets using the RemoteDispatcher:

    • send a packet and return immediately (e.g. heart beat, send a message)

      • using sendOneWay(AbstractPacket packet)

      • if the sender wants to be called back later, it must fist register a PacketHandler and set the callbackID on the packet which is sent

    • send a packet and block until a response is received (e.g. create a new session)

      • using sendBlocking(AbstractPacket packet)

     

    If the packet is targeted to be received by a specific PacketHandler, the ID of this PacketHandler must be set using the AbstractPacket.setTargetID(String) method.

     

    Packet Encoding/Decoding

     

    For each type of Packet, there are 3 pieces of code involved:

    • a unique type enumerated in PacketType enum

    • the "body" representation of the packet type (a class extending AbstractPacket with new attributes)

    • the encoding/decoding of the body of the packet type (a class extending AbstractPacketCodec)

     

    Encoding/Decoding of AbstractPacket class is handled directly by AbstractPacketCodec.

    Subclasses must only take care of encoding attributes added to AbstractPacket subclasses. It is also their responsibilities to ensure that they have received enough data to be able to decode the Packet "body" (i.e. all attributes of the subclass)

     

    Transport

     

    • Communication between clients and servers can be done on top of TCP/IP or HTTP. HTTP should be used only when TCP/IP is not possible (e.g. firewall).

    • HTTP is only used as a tunnel: packets codec is used to encode/decode packets as bytes (like for TCP/IP). They are then encoded/decoded as Base64 strings which are passed as parameters to HTTP requests and body in HTTP responses.

    • (?) when using HTTP, communication initiated by server to client is done by pushing packets (as an HTTP Response without a corresponding HTTP Request). There is no polling.

    • One-way messages sent on top of HTTP transport generates automatically an HTTP response corresponding to a "NULL" packet. This NULL packet is then discarded on the client side

    • It is currently not possible to POST HTTP requests: MINA server does not understand HTTP POST requests. We can circumvent that by sending HTTP requests with GET but this can become an issue depending on the size of the packets to transmit (+ regular issues wrt to using GET instead of POST, like side-effect, caching, etc.). This issue is tracked by ASYNCWEB-24.

    • Security using SSL/TLS can be enabled on top of both TCP/IP and HTTP

     

    Configuration

     

    • server host

    • server port

    • transport type (TCP/IP or HTTP)

    • security (SSL/TLS)