Interface Pipeline

  • All Known Implementing Classes:
    DefaultPipeline, DrasylPipeline, EmbeddedPipeline

    public interface Pipeline
    A list of Handlers which handles or intercepts inbound events and outbound operations of a DrasylNode. Pipeline implements an advanced form of the Intercepting Filter pattern to give a user full control over how an event is handled and how the Handlers in a pipeline interact with each other. This implementation is very closely based on the netty implementation.

    Creation of a pipeline

    Each per DrasylNode exists one pipeline and it is created automatically when a new node is created.

    How an event flows in a pipeline

    The following diagram describes how I/O events are processed by Handlers in a Pipeline typically. An I/O event is handled by either a InboundHandler or a OutboundHandler and be forwarded to its closest handler by calling the event propagation methods defined in HandlerContext, such as HandlerContext.fireRead(ApplicationMessage) and HandlerContext.write(ApplicationMessage).

                                                     I/O Request
                                                via HandlerContext
                                                          |
      +---------------------------------------------------+---------------+
      |                            Pipeline               |               |
      |                                                  \|/              |
      |    +---------------------+            +-----------+----------+    |
      |    | Inbound Handler  N  |            | Outbound Handler  1  |    |
      |    +----------+----------+            +-----------+----------+    |
      |              /|\                                  |               |
      |               |                                  \|/              |
      |    +----------+----------+            +-----------+----------+    |
      |    | Inbound Handler N-1 |            | Outbound Handler  2  |    |
      |    +----------+----------+            +-----------+----------+    |
      |              /|\                                  .               |
      |               .                                   .               |
      |   HandlerContext.fireIN_EVT()          HandlerContext.OUT_EVT()   |
      |        [ method call]                       [method call]         |
      |               .                                   .               |
      |               .                                  \|/              |
      |    +----------+----------+            +-----------+----------+    |
      |    | Inbound Handler  2  |            | Outbound Handler M-1 |    |
      |    +----------+----------+            +-----------+----------+    |
      |              /|\                                  |               |
      |               |                                  \|/              |
      |    +----------+----------+            +-----------+----------+    |
      |    | Inbound Handler  1  |            | Outbound Handler  M  |    |
      |    +----------+----------+            +-----------+----------+    |
      |              /|\                                  |               |
      +---------------+-----------------------------------+---------------+
                      |                                  \|/
      +---------------+-----------------------------------+---------------+
      |               |                                   |               |
      |       [ MessageSink.send() ]              [ DrasylNode.send() ]   |
      |                                                                   |
      |  drasyl Internal I/O                                              |
      +-------------------------------------------------------------------+
      

    An inbound event is handled by the inbound handlers in the bottom-up direction as shown on the left side of the diagram. An inbound handler usually handles the inbound data generated by the I/O thread on the bottom of the diagram. The inbound data is often read from a remote peer via the actual input operation such as MessageSink.send(RelayableMessage). If an inbound event goes beyond the top inbound handler, it is passed to the application.

    An outbound event is handled by the outbound handler in the top-down direction as shown on the right side of the diagram. An outbound handler usually generates or transforms the outbound traffic such as write requests. If an outbound event goes beyond the bottom outbound handler, it is handled by the Messenger.send(RelayableMessage) which performs the actual output operation.

    For example, let us assume that we created the following pipeline:

     Pipeline p = ...;
     p.addLast("1", new InboundHandlerA());
     p.addLast("2", new InboundHandlerB());
     p.addLast("3", new OutboundHandlerA());
     p.addLast("4", new OutboundHandlerB());
     p.addLast("5", new InboundOutboundHandlerX());
     
    In the example above, the class whose name starts with Inbound means it is an inbound handler. The class whose name starts with Outbound means it is a outbound handler.

    In the given example configuration, the handler evaluation order is 1, 2, 3, 4, 5 when an event goes inbound. When an event goes outbound, the order is 5, 4, 3, 2, 1. On top of this principle, Pipeline skips the evaluation of certain handlers to shorten the stack depth:

    • 3 and 4 don't implement InboundHandler, and therefore the actual evaluation order of an inbound event will be: 1, 2, and 5.
    • 1 and 2 don't implement OutboundHandler, and therefore the actual evaluation order of a outbound event will be: 5, 4, and 3.
    • If 5 implements both InboundHandler and OutboundHandler, the evaluation order of an inbound and a outbound event could be 125 and 543 respectively.

    Forwarding an event to the next handler

    As you might noticed in the diagram shows, a handler has to invoke the event propagation methods in HandlerContext to forward an event to its next handler. Those methods include:

    Thread safety

    A Handler can be added or removed at any time because a Pipeline is thread safe.

  • But for every invocation of:
  • the invocation is scheduled in the DrasylScheduler, therefore the order of invocations can't be guaranteed. You have to ensure by yourself, that your handlers are thread-safe if you need it. Also, you have to ensure the order of messages, if you need it.