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 are handled by a Handler and be forwarded to its closest handler by calling the event propagation methods defined in HandlerContext, such as HandlerContext.fireRead(Address, Object, CompletableFuture) and HandlerContext.write(Address, Object, CompletableFuture) .

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

An inbound event is handled by the handlers in the bottom-up direction as shown on the left side of the diagram. A 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. If an inbound event goes beyond the top handler, it is passed to the application.

An outbound event is handled by the handler in the top-down direction as shown on the right side of the diagram. A handler usually generates or transforms the outbound traffic such as write requests.

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

 Pipeline p = ...;
 p.addLast("1", new HandlerA());
 p.addLast("2", new HandlerB());
 p.addLast("3", new HandlerC());
 p.addLast("4", new HandlerD());
 p.addLast("5", new HandlerE());
 
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.

Forwarding an event to the next handler

As you might noticed in the diagram, 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.
    • Method Details

      • addFirst

        Pipeline addFirst(String name, Handler handler)
        Inserts a Handler at the first position of this pipeline.
        Parameters:
        name - the name of the handler to insert first
        handler - the handler to insert first
        Throws:
        IllegalArgumentException - if there's an entry with the same name already in the pipeline
        NullPointerException - if the specified handler is null
      • addLast

        Pipeline addLast(String name, Handler handler)
        Appends a Handler at the last position of this pipeline.
        Parameters:
        name - the name of the handler to append
        handler - the handler to append
        Throws:
        IllegalArgumentException - if there's an entry with the same name already in the pipeline
        NullPointerException - if the specified handler is null
      • addBefore

        Pipeline addBefore(String baseName, String name, Handler handler)
        Inserts a Handler before an existing handler of this pipeline.
        Parameters:
        baseName - the name of the existing handler
        name - the name of the handler to insert before
        handler - the handler to insert before
        Throws:
        NoSuchElementException - if there's no such entry with the specified baseName
        IllegalArgumentException - if there's an entry with the same name already in the pipeline
        NullPointerException - if the specified baseName or handler is null
      • addAfter

        Pipeline addAfter(String baseName, String name, Handler handler)
        Inserts a Handler after an existing handler of this pipeline.
        Parameters:
        baseName - the name of the existing handler
        name - the name of the handler to insert after
        handler - the handler to insert after
        Throws:
        NoSuchElementException - if there's no such entry with the specified baseName
        IllegalArgumentException - if there's an entry with the same name already in the pipeline
        NullPointerException - if the specified baseName or handler is null
      • remove

        Pipeline remove(String name)
        Removes the Handler with the specified name from this pipeline.
        Parameters:
        name - the name under which the Handler was stored.
        Throws:
        NoSuchElementException - if there's no such handler with the specified name in this pipeline
        NullPointerException - if the specified name is null
      • replace

        Pipeline replace(String oldName, String newName, Handler newHandler)
        Replaces the Handler of the specified name with a new handler in this pipeline.
        Parameters:
        oldName - the name of the Handler to be replaced
        newName - the name under which the replacement should be added
        newHandler - the Handler which is used as replacement
        Throws:
        NoSuchElementException - if the handler with the specified old name does not exist in this pipeline
        IllegalArgumentException - if a handler with the specified new name already exists in this pipeline, except for the handler to be replaced
        NullPointerException - if the specified old handler or new handler is null
      • get

        Handler get(String name)
        Returns the Handler with the specified name in this pipeline.
        Returns:
        the handler with the specified name. null if there's no such handler in this pipeline.
      • context

        HandlerContext context(String name)
        Returns the context object of the Handler with the specified name in this pipeline.
        Returns:
        the context object of the handler with the specified name. null if there's no such handler in this pipeline.
      • processInbound

        CompletableFuture<Void> processInbound(Address sender, Object msg)
        Processes an inbound message by the pipeline.
        Parameters:
        sender - the sender of the message
        msg - the inbound message
      • processInbound

        CompletableFuture<Void> processInbound(Message msg)
        Processes an inbound message by the pipeline.
        Parameters:
        msg - the inbound message
      • processInbound

        CompletableFuture<Void> processInbound(Event event)
        Processes an inbound event by the pipeline.
        Parameters:
        event - the inbound event
      • processOutbound

        CompletableFuture<Void> processOutbound(Address recipient, Object msg)
        Processes an outbound message by the pipeline.
        Parameters:
        recipient - the recipient of the message
        msg - the outbound message
        Returns:
        a completed future if the message was successfully processed, otherwise an exceptionally future