All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.refcodes.serial.ext.handshake.HandshakePortController Maven / Gradle / Ivy

Go to download

The refcodes-serial-ext-handshake artifact extends the refcodes-serial artifact with handshake functionality.

The newest version!
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.serial.ext.handshake;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.refcodes.controlflow.ControlFlowUtility;
import org.refcodes.data.IoRetryCount;
import org.refcodes.data.IoSleepLoopTime;
import org.refcodes.exception.TimeoutIOException;
import org.refcodes.exception.Trap;
import org.refcodes.io.TimeoutInputStream;
import org.refcodes.numerical.ChecksumValidationMode;
import org.refcodes.numerical.ChecksumValidationModeAccessor;
import org.refcodes.numerical.CrcAlgorithm;
import org.refcodes.numerical.CrcAlgorithmAccessor;
import org.refcodes.numerical.Endianess;
import org.refcodes.numerical.EndianessAccessor;
import org.refcodes.serial.AbstractPortDecorator;
import org.refcodes.serial.AcknowledgeMagicBytesAccessor;
import org.refcodes.serial.AcknowledgeRetryNumberAccessor;
import org.refcodes.serial.AcknowledgeTimeoutMillisAccessor;
import org.refcodes.serial.AllocSectionDecoratorSegment;
import org.refcodes.serial.AssertMagicBytesSegment;
import org.refcodes.serial.ByteArraySection;
import org.refcodes.serial.ByteSegment;
import org.refcodes.serial.MagicBytesSegmentMultiplexer;
import org.refcodes.serial.Port;
import org.refcodes.serial.PortMetrics;
import org.refcodes.serial.ReceiveSegmentConsumerDaemon;
import org.refcodes.serial.ReceiveSegmentResultDaemon;
import org.refcodes.serial.Segment;
import org.refcodes.serial.SegmentConsumer;
import org.refcodes.serial.SegmentResult;
import org.refcodes.serial.Sequence;
import org.refcodes.serial.SequenceNumberAccessor;
import org.refcodes.serial.SequenceNumberInitValueAccessor;
import org.refcodes.serial.SequenceNumberWidthAccessor;
import org.refcodes.serial.SerialUtility;
import org.refcodes.serial.TransmissionException;
import org.refcodes.serial.TransmitSegmentConsumerDaemon;
import org.refcodes.serial.TransmitSegmentResultDaemon;

/**
 * A {@link HandshakePortController} decorates a {@link Port} for its usage in
 * Full-Duplex mode regarding the transmission of {@link Segment} messages (or
 * any transmission finished off by calling {@link #flush()}). This is achieved
 * by giving each {@link Segment} (or transmission) to be transmitted a sequence
 * number together with magic bytes identifying the transmission as being a
 * {@link Segment}. Each acknowledge message is given the sequence numbers of
 * successfully received {@link Segment} transmissions alongside magic bytes
 * identifying the acknowledge message as such. This way {@link Segment}
 * messages and acknowledge messages can be distinguished from each other and
 * transmission can take place in Full-Duplex mode. This implementation applies
 * the Full-Duplex handshake on {@link Segment} messages rather than on packets
 * (of a defined size) in order to enable microcontroller based implementation
 * to participate easily in this kind of Full-Duplex. Caution: In case very much
 * data (long transmissions) is to be transmitted, then the outbound line will
 * be blocked by the transmission so that for the time of sending the
 * transmission No-Acknowledge message upon receival of an inbound transmission
 * can be sent over the outbound line! For such use cases sending much data in a
 * single transmission, consider chunking a big transmission into packages
 * (could be done by a https://www.metacodes.proization of the
 * {@link HandshakePortController}).
 * 
 * @param  The actual {@link PortMetrics} type to use.
 */
public class HandshakePortController extends AbstractPortDecorator implements AcknowledgeMagicBytesAccessor, AcknowledgeTimeoutMillisAccessor, AcknowledgeRetryNumberAccessor, ReplyTimeoutMillisAccessor, ReplyRetryNumberAccessor, SequenceNumberAccessor, SequenceNumberInitValueAccessor, SequenceNumberWidthAccessor, CrcAlgorithmAccessor, ChecksumValidationModeAccessor, EndianessAccessor { // ExceptionHandlerMutator, ExceptionHandlerBuilder> 

	// /////////////////////////////////////////////////////////////////////////
	// STATICS:
	// /////////////////////////////////////////////////////////////////////////

	private static final Logger LOGGER = Logger.getLogger( HandshakePortController.class.getName() );

	// /////////////////////////////////////////////////////////////////////////
	// CONSTANTS:
	// /////////////////////////////////////////////////////////////////////////

	private static final int MAX_SEQUENCE_NUMBER_COUNT = 1024;

	// /////////////////////////////////////////////////////////////////////////
	// VARIABLES:
	// /////////////////////////////////////////////////////////////////////////

	private final Set _sequenceNumbers = new HashSet<>();
	private LinkedBlockingQueue _inboundQueue;
	private final LinkedBlockingQueue _consumerQueue = new LinkedBlockingQueue<>();
	private final LinkedBlockingQueue _requestQueue = new LinkedBlockingQueue<>();
	private final LinkedBlockingQueue _outboundQueue = new LinkedBlockingQueue<>();
	private final AtomicInteger _sequenceNumber = new AtomicInteger( 0 );
	private final Map _sequenceNumToAcknowledge = new HashMap<>();
	private final Map _sequenceNumToRequest = new HashMap<>();
	private HandshakeTransmissionMetrics _transmissionMetrics;
	private final List> _segmentConsumerTupels = new ArrayList<>();
	private final List> _requestHandlerTupels = new ArrayList<>();
	private Runnable _pingHandler = null;
	private ExecutorService _executorService;

	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTORS:
	// /////////////////////////////////////////////////////////////////////////

	private HandshakePortController( Builder aBuilder ) {
		this( aBuilder.port, aBuilder.endianess, aBuilder.acknowledgeRetryNumber, aBuilder.acknowledgeTimeoutInMs, aBuilder.replyRetryNumber, aBuilder.replyTimeoutInMs, aBuilder.sequenceNumberInitValue, aBuilder.sequenceNumberWidth, aBuilder.crcAlgorithm, aBuilder.checksumValidationMode, aBuilder.inboundQueueCapacity, aBuilder.executorService );
	}

	// -------------------------------------------------------------------------

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
	 *        be used for configuring this instance.
	 */
	public HandshakePortController( Port aPort, HandshakeTransmissionMetrics aTransmissionMetrics ) {
		this( aPort, aTransmissionMetrics, -1, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
	 *        be used for configuring this instance.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, HandshakeTransmissionMetrics aTransmissionMetrics, ExecutorService aExecutorService ) {
		this( aPort, aTransmissionMetrics, -1, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 */
	public HandshakePortController( Port aPort ) {
		this( aPort, null, -1, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 *
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aAcknowledgeRetryNumber The number of retries waiting for an ACK
	 *        from the return channel.
	 * @param aAcknowledgeTimeoutInMs The timeout in milliseconds to pend till
	 *        the next retry.
	 * @param aReplyRetryNumber The number of retries waiting for a reply from
	 *        the return channel.
	 * @param aReplyTimeoutInMs The timeout in milliseconds to pend till the
	 *        next retry.
	 * @param aSequenceNumberWidth The width in bytes to be used for the binary
	 *        sequence number representation.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, int aAcknowledgeRetryNumber, long aAcknowledgeTimeoutInMs, int aReplyRetryNumber, long aReplyTimeoutInMs, int aSequenceNumberWidth, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode ) {
		this( aPort, aEndianess, aAcknowledgeRetryNumber, aAcknowledgeTimeoutInMs, aReplyRetryNumber, aReplyTimeoutInMs, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, aSequenceNumberWidth, aCrcAlgorithm, aChecksumValidationMode, -1, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 *
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aAcknowledgeRetryNumber The number of retries waiting for an ACK
	 *        from the return channel.
	 * @param aAcknowledgeTimeoutInMs The timeout in milliseconds to pend till
	 *        the next retry.
	 * @param aReplyRetryNumber The number of retries waiting for a reply from
	 *        the return channel.
	 * @param aReplyTimeoutInMs The timeout in milliseconds to pend till the
	 *        next retry.
	 * @param aSequenceNumberWidth The width in bytes to be used for the binary
	 *        sequence number representation.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, int aAcknowledgeRetryNumber, long aAcknowledgeTimeoutInMs, int aReplyRetryNumber, long aReplyTimeoutInMs, int aSequenceNumberWidth, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode, ExecutorService aExecutorService ) {
		this( aPort, aEndianess, aAcknowledgeRetryNumber, aAcknowledgeTimeoutInMs, aReplyRetryNumber, aReplyTimeoutInMs, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, aSequenceNumberWidth, aCrcAlgorithm, aChecksumValidationMode, -1, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 *
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aAcknowledgeRetryNumber The number of retries waiting for an ACK
	 *        from the return channel.
	 * @param aAcknowledgeTimeoutInMs The timeout in milliseconds to pend till
	 *        the next retry.
	 * @param aReplyRetryNumber The number of retries waiting for a reply from
	 *        the return channel.
	 * @param aReplyTimeoutInMs The timeout in milliseconds to pend till the
	 *        next retry.
	 * @param aSequenceNumberInitValue The initialization value for the sequence
	 *        number counter, when -1 then the lower 32 bit of the current time
	 *        in milliseconds are taken to prevent sequence number collisions
	 *        upon restarting one of the two communication partners.
	 * @param aSequenceNumberWidth The width in bytes to be used for the binary
	 *        sequence number representation.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, int aAcknowledgeRetryNumber, long aAcknowledgeTimeoutInMs, int aReplyRetryNumber, long aReplyTimeoutInMs, int aSequenceNumberInitValue, int aSequenceNumberWidth, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode ) {
		this( aPort, aEndianess, aAcknowledgeRetryNumber, aAcknowledgeTimeoutInMs, aReplyRetryNumber, aReplyTimeoutInMs, aSequenceNumberInitValue, aSequenceNumberWidth, aCrcAlgorithm, aChecksumValidationMode, -1, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, CrcAlgorithm aCrcAlgorithm ) {
		this( aPort, aEndianess, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_REPLY_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_REPLY_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_WIDTH, aCrcAlgorithm, HandshakeTransmissionMetrics.DEFAULT_CHECKSUM_VALIDATION_MODE, -1, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode ) {
		this( aPort, aEndianess, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_REPLY_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_REPLY_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_WIDTH, aCrcAlgorithm, aChecksumValidationMode, -1, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode, ExecutorService aExecutorService ) {
		this( aPort, aEndianess, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_REPLY_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_REPLY_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_WIDTH, aCrcAlgorithm, aChecksumValidationMode, -1, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, CrcAlgorithm aCrcAlgorithm, ExecutorService aExecutorService ) {
		this( aPort, aEndianess, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_REPLY_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_REPLY_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_WIDTH, aCrcAlgorithm, HandshakeTransmissionMetrics.DEFAULT_CHECKSUM_VALIDATION_MODE, -1, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, ExecutorService aExecutorService ) {
		this( aPort, HandshakeTransmissionMetrics.DEFAULT_ENDIANESS, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_REPLY_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_REPLY_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_WIDTH, HandshakeTransmissionMetrics.DEFAULT_CRC_ALGORITHM, HandshakeTransmissionMetrics.DEFAULT_CHECKSUM_VALIDATION_MODE, -1, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
	 *        be used for configuring this instance.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 */
	public HandshakePortController( Port aPort, HandshakeTransmissionMetrics aTransmissionMetrics, int aInboundQueueCapacity ) {
		this( aPort, aTransmissionMetrics, aInboundQueueCapacity, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 */
	public HandshakePortController( Port aPort, int aInboundQueueCapacity ) {
		this( aPort, null, aInboundQueueCapacity, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 *
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aAcknowledgeRetryNumber The number of retries waiting for an ACK
	 *        from the return channel.
	 * @param aAcknowledgeTimeoutInMs The timeout in milliseconds to pend till
	 *        the next retry.
	 * @param aReplyRetryNumber The number of retries waiting for a reply from
	 *        the return channel.
	 * @param aReplyTimeoutInMs The timeout in milliseconds to pend till the
	 *        next retry.
	 * @param aSequenceNumberWidth The width in bytes to be used for the binary
	 *        sequence number representation.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, int aAcknowledgeRetryNumber, long aAcknowledgeTimeoutInMs, int aReplyRetryNumber, long aReplyTimeoutInMs, int aSequenceNumberWidth, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode, int aInboundQueueCapacity ) {
		this( aPort, aEndianess, aAcknowledgeRetryNumber, aAcknowledgeTimeoutInMs, aReplyRetryNumber, aReplyTimeoutInMs, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, aSequenceNumberWidth, aCrcAlgorithm, aChecksumValidationMode, aInboundQueueCapacity, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 *
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aAcknowledgeRetryNumber The number of retries waiting for an ACK
	 *        from the return channel.
	 * @param aAcknowledgeTimeoutInMs The timeout in milliseconds to pend till
	 *        the next retry.
	 * @param aReplyRetryNumber The number of retries waiting for a reply from
	 *        the return channel.
	 * @param aReplyTimeoutInMs The timeout in milliseconds to pend till the
	 *        next retry.
	 * @param aSequenceNumberWidth The width in bytes to be used for the binary
	 *        sequence number representation.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, int aAcknowledgeRetryNumber, long aAcknowledgeTimeoutInMs, int aReplyRetryNumber, long aReplyTimeoutInMs, int aSequenceNumberWidth, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode, int aInboundQueueCapacity, ExecutorService aExecutorService ) {
		this( aPort, aEndianess, aAcknowledgeRetryNumber, aAcknowledgeTimeoutInMs, aReplyRetryNumber, aReplyTimeoutInMs, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, aSequenceNumberWidth, aCrcAlgorithm, aChecksumValidationMode, aInboundQueueCapacity, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 *
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aAcknowledgeRetryNumber The number of retries waiting for an ACK
	 *        from the return channel.
	 * @param aAcknowledgeTimeoutInMs The timeout in milliseconds to pend till
	 *        the next retry.
	 * @param aReplyRetryNumber The number of retries waiting for a reply from
	 *        the return channel.
	 * @param aReplyTimeoutInMs The timeout in milliseconds to pend till the
	 *        next retry.
	 * @param aSequenceNumberInitValue The initialization value for the sequence
	 *        number counter, when -1 then the lower 32 bit of the current time
	 *        in milliseconds are taken to prevent sequence number collisions
	 *        upon restarting one of the two communication partners.
	 * @param aSequenceNumberWidth The width in bytes to be used for the binary
	 *        sequence number representation.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, int aAcknowledgeRetryNumber, long aAcknowledgeTimeoutInMs, int aReplyRetryNumber, long aReplyTimeoutInMs, int aSequenceNumberInitValue, int aSequenceNumberWidth, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode, int aInboundQueueCapacity ) {
		this( aPort, aEndianess, aAcknowledgeRetryNumber, aAcknowledgeTimeoutInMs, aReplyRetryNumber, aReplyTimeoutInMs, aSequenceNumberInitValue, aSequenceNumberWidth, aCrcAlgorithm, aChecksumValidationMode, aInboundQueueCapacity, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, CrcAlgorithm aCrcAlgorithm, int aInboundQueueCapacity ) {
		this( aPort, aEndianess, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_REPLY_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_REPLY_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_WIDTH, aCrcAlgorithm, HandshakeTransmissionMetrics.DEFAULT_CHECKSUM_VALIDATION_MODE, aInboundQueueCapacity, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode, int aInboundQueueCapacity ) {
		this( aPort, aEndianess, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_REPLY_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_REPLY_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_WIDTH, aCrcAlgorithm, aChecksumValidationMode, aInboundQueueCapacity, null );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode, int aInboundQueueCapacity, ExecutorService aExecutorService ) {
		this( aPort, aEndianess, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_REPLY_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_REPLY_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_WIDTH, aCrcAlgorithm, aChecksumValidationMode, aInboundQueueCapacity, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, CrcAlgorithm aCrcAlgorithm, int aInboundQueueCapacity, ExecutorService aExecutorService ) {
		this( aPort, aEndianess, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_ACKNOWLEDGE_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_REPLY_RETRY_NUMBER, HandshakeTransmissionMetrics.DEFAULT_REPLY_TIMEOUT_IN_MS, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_INIT_VALUE, HandshakeTransmissionMetrics.DEFAULT_SEQUENCE_NUMBER_WIDTH, aCrcAlgorithm, HandshakeTransmissionMetrics.DEFAULT_CHECKSUM_VALIDATION_MODE, aInboundQueueCapacity, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, int aInboundQueueCapacity, ExecutorService aExecutorService ) {
		this( aPort, null, aInboundQueueCapacity, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 *
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aAcknowledgeRetryNumber The number of retries waiting for an ACK
	 *        from the return channel.
	 * @param aAcknowledgeTimeoutInMs The timeout in milliseconds to pend till
	 *        the next retry.
	 * @param aReplyRetryNumber The number of retries waiting for a reply from
	 *        the return channel.
	 * @param aReplyTimeoutInMs The timeout in milliseconds to pend till the
	 *        next retry.
	 * @param aSequenceNumberInitValue The initialization value for the sequence
	 *        number counter, when -1 then the lower 32 bit of the current time
	 *        in milliseconds are taken to prevent sequence number collisions
	 *        upon restarting one of the two communication partners.
	 * @param aSequenceNumberWidth The width in bytes to be used for the binary
	 *        sequence number representation.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, int aAcknowledgeRetryNumber, long aAcknowledgeTimeoutInMs, int aReplyRetryNumber, long aReplyTimeoutInMs, int aSequenceNumberInitValue, int aSequenceNumberWidth, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode, ExecutorService aExecutorService ) {
		this( aPort, aEndianess, aAcknowledgeRetryNumber, aAcknowledgeTimeoutInMs, aReplyRetryNumber, aReplyTimeoutInMs, aSequenceNumberInitValue, aSequenceNumberWidth, aCrcAlgorithm, aChecksumValidationMode, -1, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 *
	 * @param aPort The {@link Port} to be decorated.
	 * @param aEndianess The {@link Endianess} to use when calculating the CRC
	 *        checksum.
	 * @param aAcknowledgeRetryNumber The number of retries waiting for an ACK
	 *        from the return channel.
	 * @param aAcknowledgeTimeoutInMs The timeout in milliseconds to pend till
	 *        the next retry.
	 * @param aReplyRetryNumber The number of retries waiting for a reply from
	 *        the return channel.
	 * @param aReplyTimeoutInMs The timeout in milliseconds to pend till the
	 *        next retry.
	 * @param aSequenceNumberInitValue The initialization value for the sequence
	 *        number counter, when -1 then the lower 32 bit of the current time
	 *        in milliseconds are taken to prevent sequence number collisions
	 *        upon restarting one of the two communication partners.
	 * @param aSequenceNumberWidth The width in bytes to be used for the binary
	 *        sequence number representation.
	 * @param aCrcAlgorithm The {@link CrcAlgorithm} to be used for CRC checksum
	 *        calculation.
	 * @param aChecksumValidationMode The mode of operation when validating
	 *        provided CRC checksums against calculated ones.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, Endianess aEndianess, int aAcknowledgeRetryNumber, long aAcknowledgeTimeoutInMs, int aReplyRetryNumber, long aReplyTimeoutInMs, int aSequenceNumberInitValue, int aSequenceNumberWidth, CrcAlgorithm aCrcAlgorithm, ChecksumValidationMode aChecksumValidationMode, int aInboundQueueCapacity, ExecutorService aExecutorService ) {
		this( aPort, HandshakeTransmissionMetrics.builder().withEndianess( aEndianess ).withAcknowledgeRetryNumber( aAcknowledgeRetryNumber ).withAcknowledgeTimeoutMillis( aAcknowledgeTimeoutInMs ).withSequenceNumberInitValue( aSequenceNumberInitValue ).withSequenceNumberWidth( aSequenceNumberWidth ).withCrcAlgorithm( aCrcAlgorithm ).withChecksumValidationMode( aChecksumValidationMode ).build(), aInboundQueueCapacity, aExecutorService );
	}

	/**
	 * Decorates the given {@link Port} with full duplex {@link Segment}
	 * multiplexer functionality as of the given arguments.
	 * 
	 * @param aPort The {@link Port} to be decorated.
	 * @param aTransmissionMetrics The {@link HandshakeTransmissionMetrics} to
	 *        be used for configuring this instance.
	 * @param aInboundQueueCapacity The capacity of the inbound queue, any
	 *        exceeding inbound transmissions are skipped.
	 * @param aExecutorService The {@link ExecutorService} to be used when
	 *        creating {@link Thread} instances for handling input and output
	 *        data simultaneously.
	 */
	public HandshakePortController( Port aPort, HandshakeTransmissionMetrics aTransmissionMetrics, int aInboundQueueCapacity, ExecutorService aExecutorService ) {
		super( aPort );
		_inboundQueue = new LinkedBlockingQueue<>( aInboundQueueCapacity != -1 ? aInboundQueueCapacity : Integer.MAX_VALUE );
		_transmissionMetrics = aTransmissionMetrics != null ? aTransmissionMetrics : new HandshakeTransmissionMetrics();
		_sequenceNumber.set( _transmissionMetrics.getSequenceNumberInitValue() != -1 ? _transmissionMetrics.getSequenceNumberInitValue() : (int) System.currentTimeMillis() );
		_executorService = ( aExecutorService != null ) ? aExecutorService : ControlFlowUtility.createCachedExecutorService( true );
		if ( aPort.isOpened() ) { // Is the provided port already open?
			start();
		}
	}

	// /////////////////////////////////////////////////////////////////////////
	// METHODS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Probes the connection by sending a "ping" to the attached remote station
	 * ({@link HandshakePortController}) expecting a "pong" reply within a
	 * timeout (shorter than the timeout of usual transmissions).
	 * 
	 * @throws IOException thrown in case the "ping" failed, e.g. the remote
	 *         station ({@link HandshakePortController}) is not ready
	 *         (available).
	 */
	public void ping() throws IOException {
		pingWithin( _transmissionMetrics.getPingTimeoutMillis(), _transmissionMetrics.getPingRetryNumber() );
	}

	/**
	 * Probes the connection by sending a "ping" to the attached remote station
	 * ({@link HandshakePortController}) expecting a "pong" reply within a
	 * timeout (shorter than the timeout of usual transmissions).
	 *
	 * @param  the generic type
	 * @param aTimeoutMillis The timeout to wait for sending the ping and
	 *        receiving the pong till aborting.
	 * @param aRetryNumber The number of retries each of the given timeout in
	 *        milliseconds.
	 * 
	 * @throws IOException thrown in case the "ping" failed, e.g. the remote
	 *         station ({@link HandshakePortController}) is not ready
	 *         (available).
	 */
	public  void pingWithin( long aTimeoutMillis, int aRetryNumber ) throws IOException {
		transmitSegmentWithin( aTimeoutMillis, aRetryNumber, new TransmissionMessage( _sequenceNumber.getAndIncrement(), TransmissionType.PING, _transmissionMetrics ) );
	}

	/**
	 * Registers a handler invoked upon incoming remote ping requests (via a
	 * remote's invocation of {@link #ping()} or similar). The according
	 * acknowledgement ("pong") is sent automatically, though the ping handler
	 * should be short running as the ping's acknowledgment timeouts are usually
	 * shorter than other transmission related timeouts.
	 * 
	 * @param aPingHandler The handler to be notified upon incoming ping
	 *        requests.
	 */
	public void onPing( Runnable aPingHandler ) {
		_pingHandler = aPingHandler;
	}

	/**
	 * Adds a {@link SegmentConsumer} for receiving and handling transmissions.
	 * 
	 * @param  The type of {@link Segment} for which to register.
	 * @param aSegment The {@link Segment} used for deserializing the
	 *        transmission. A good practice is to use some kind of
	 *        {@link AssertMagicBytesSegment} for uniquely identifying a
	 *        responsible {@link SegmentConsumer} for an according
	 *        {@link Segment}.
	 * @param aSegmentConsumer The {@link SegmentConsumer} processing the
	 *        according transmission.
	 * 
	 * @return True in case the {@link SegmentConsumer} has been registered to
	 *         the given {@link Segment}, false in case a consumer has already
	 *         been registered to the given segment.
	 */
	public  boolean onSegment( SEGMENT aSegment, SegmentConsumer aSegmentConsumer ) {
		for ( SegmentConsumerTupel eTupel : _segmentConsumerTupels ) {
			if ( eTupel.segment == aSegment || eTupel.segment.equals( aSegment ) ) {
				return false;
			}
		}
		_segmentConsumerTupels.add( new SegmentConsumerTupel<>( aSegment, aSegmentConsumer ) );
		return true;
	}

	/**
	 * Removes a registered {@link SegmentConsumer} (as of
	 * {@link #subscribeSegmentConsumer(Segment, SegmentConsumer)}).
	 *
	 * @param  the generic type
	 * @param aRequest the request
	 * @param aRequestHandler the request handler
	 * 
	 * @return True in case the {@link SegmentConsumer} was removed, false in
	 *         case no such {@link SegmentConsumer} was found.
	 */
	//	public  boolean unsubscribeSegmentConsumer( SEGMENT aSegment ) {
	//		Iterator> e = _segmentConsumerTupels.iterator();
	//		while ( e.hasNext() ) {
	//			if ( e.next().segment == aSegment ) {
	//				e.remove();
	//				return true;
	//			}
	//		}
	//		return false;
	//	}

	/**
	 * Adds a {@link RequestHandler} for processing requests issued as of
	 * {@link #requestSegment(Segment, Segment)} (and the like methods).
	 * 
	 * @param  The type of {@link Segment} for which to register.
	 * @param aRequest The request {@link Segment} used for deserialize the
	 *        request. A good practice is to use some kind of
	 *        {@link AssertMagicBytesSegment} for uniquely identify a
	 *        responsible {@link RequestHandler} for an according
	 *        {@link Segment}.
	 * @param aRequestHandler The {@link RequestHandler} processing the
	 *        according request.
	 * 
	 * @return True in case the {@link RequestHandler} has been registered to
	 *         the given {@link Segment}, false in case a handler has already
	 *         been registered to the given request.
	 * 
	 */
	public  boolean onRequest( REQUEST aRequest, RequestHandler aRequestHandler ) {
		for ( RequestHandlerTupel eTupel : _requestHandlerTupels ) {
			if ( eTupel.request == aRequest || eTupel.request.equals( aRequest ) ) {
				return false;
			}
		}
		_requestHandlerTupels.add( new RequestHandlerTupel<>( aRequest, aRequestHandler ) );
		return true;
	}

	/**
	 * Removes a registered {@link RequestHandler} (as of
	 * {@link #subscribeRequestHandler(Segment, RequestHandler)}).
	 *
	 * @return True in case the {@link RequestHandler} was removed, false in
	 *         case no such {@link RequestHandler} was found.
	 * 
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	//	public  boolean unsubscribeRequestHandler( REQUEST aRequest ) {
	//		Iterator> e = _requestHandlerTupels.iterator();
	//		while ( e.hasNext() ) {
	//			if ( e.next().request == aRequest ) {
	//				e.remove();
	//				return true;
	//			}
	//		}
	//		return false;
	//	}

	//	/**
	//	 * {@inheritDoc}
	//	 */
	//	@Override
	//	public FullDuplexHandshakePortDecorator withExceptionHandler( ExceptionHandler aExceptionHandler ) {
	//		_exceptionHandler = aExceptionHandler;
	//		return this;
	//	}

	//	/**
	//	 * {@inheritDoc}
	//	 */
	//	@Override
	//	public void setExceptionHandler( ExceptionHandler aExceptionHandler ) {
	//		_exceptionHandler = aExceptionHandler;
	//	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int available() throws IOException {
		final List theSegments = new ArrayList<>( _inboundQueue );
		int theLength = 0;
		for ( Segment eSegment : theSegments ) {
			theLength += eSegment.getLength();
		}
		return theLength;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized void close() throws IOException {
		if ( _port != null ) {
			_port.close();
		}
		super.close();
		_executorService.shutdownNow();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  SegmentResult doTransmitSegment( SEGMENT aSegment ) throws IOException {
		if ( !isOpened() ) {
			throw new IOException( "Cannot receive a segment as the connection is in status <" + getConnectionStatus() + ">!" );
		}
		final TransmitSegmentResultDaemon theDaemon = new TransmitSegmentResultDaemon<>( aSegment, this );
		_executorService.execute( theDaemon );
		return theDaemon.getSegmentResult();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  void doTransmitSegment( SEGMENT aSegment, SegmentConsumer aSegmentConsumer ) throws IOException {
		if ( !isOpened() ) {
			throw new IOException( "Cannot transmit a segment as the connection is in status <" + getConnectionStatus() + ">!" );
		}
		_executorService.execute( new TransmitSegmentConsumerDaemon( aSegmentConsumer, aSegment, this ) );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public byte[] getAcknowledgeMagicBytes() {
		return _transmissionMetrics.getAcknowledgeMagicBytes();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getAcknowledgeRetryNumber() {
		return _transmissionMetrics.getAcknowledgeRetryNumber();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public long getAcknowledgeTimeoutMillis() {
		return _transmissionMetrics.getAcknowledgeTimeoutMillis();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getReplyRetryNumber() {
		return _transmissionMetrics.getReplyRetryNumber();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public long getReplyTimeoutMillis() {
		return _transmissionMetrics.getReplyTimeoutMillis();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public CrcAlgorithm getCrcAlgorithm() {
		return _transmissionMetrics.getCrcAlgorithm();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public ChecksumValidationMode getChecksumValidationMode() {
		return _transmissionMetrics.getChecksumValidationMode();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Endianess getEndianess() {
		return _transmissionMetrics.getEndianess();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public InputStream getInputStream() {
		final TransmissionMessage theTransmissionMessage;
		InputStream thePayloadStream;
		try {
			theTransmissionMessage = _inboundQueue.take();
			thePayloadStream = theTransmissionMessage.getPayload().toSequence().getInputStream();
		}
		catch ( InterruptedException e ) {
			thePayloadStream = new ByteArrayInputStream( new byte[0] );
		}
		return thePayloadStream;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public TimeoutInputStream getInputStream( long aTimeoutMillis ) {
		return SerialUtility.createTimeoutInputStream( getInputStream(), aTimeoutMillis );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getSequenceNumber() {
		return _sequenceNumber.get();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getSequenceNumberInitValue() {
		return _transmissionMetrics.getSequenceNumberInitValue();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getSequenceNumberWidth() {
		return _transmissionMetrics.getSequenceNumberWidth();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  SegmentResult onReceiveSegment( SEGMENT aSegment ) throws IOException {
		if ( !isOpened() ) {
			throw new IOException( "Cannot receive a segment as the connection is in status <" + getConnectionStatus() + ">!" );
		}
		final ReceiveSegmentResultDaemon theDaemon = new ReceiveSegmentResultDaemon<>( aSegment, this );
		_executorService.execute( theDaemon );
		return theDaemon.getSegmentResult();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  void onReceiveSegment( SEGMENT aSegment, SegmentConsumer aSegmentConsumer ) throws IOException {
		if ( !isOpened() ) {
			throw new IOException( "Cannot receive a segment as the connection is in status <" + getConnectionStatus() + ">!" );
		}
		_executorService.execute( new ReceiveSegmentConsumerDaemon( aSegmentConsumer, aSegment, this ) );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized void open() throws IOException {
		super.open();
		start();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public synchronized void open( PM aPortMetrics ) throws IOException {
		super.open( aPortMetrics );
		start();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses a {@link ByteSegment} instance for wrapping up the receival of a
	 * single byte.
	 */
	@Override
	public byte receiveByte() throws IOException {
		return receiveByteWithin( -1 );
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses a {@link ByteSegment} instance for wrapping up the receival of a
	 * single byte.
	 */
	@Override
	public byte receiveByteWithin( long aTimeoutMillis ) throws IOException {
		ByteSegment theSegment = new ByteSegment();
		receiveSegmentWithin( aTimeoutMillis, theSegment );
		return theSegment.getPayload();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses an {@link AllocSectionDecoratorSegment} instance wrapping a
	 * {@link ByteArraySection} instance for receiving all currently available
	 * (as of {@link #available()}) bytes. Be sure you really want to use this
	 * method as the available number of bytes usually is very depended on the
	 * point in time when this method is called!
	 */
	@Override
	public byte[] receiveAllBytes() throws IOException {
		ByteArraySection theSection = new ByteArraySection( new byte[available()] );
		AllocSectionDecoratorSegment theSegment = new AllocSectionDecoratorSegment( theSection, _transmissionMetrics );
		receiveSegmentWithin( -1, theSegment );
		return theSection.getPayload();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses an {@link AllocSectionDecoratorSegment} instance wrapping a
	 * {@link ByteArraySection} instance for receiving the number of specified
	 * bytes.
	 */
	@Override
	public byte[] receiveBytes( int aLength ) throws IOException {
		return receiveBytesWithin( -1, aLength );
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses an {@link AllocSectionDecoratorSegment} instance wrapping a
	 * {@link ByteArraySection} instance for receiving the number of specified
	 * bytes.
	 */
	@Override
	public byte[] receiveBytesWithin( long aTimeoutMillis, int aLength ) throws IOException {
		ByteArraySection theSection = new ByteArraySection( new byte[aLength] );
		AllocSectionDecoratorSegment theSegment = new AllocSectionDecoratorSegment( theSection, _transmissionMetrics );
		receiveSegmentWithin( -1, theSegment );
		return theSection.getPayload();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses an {@link AllocSectionDecoratorSegment} instance wrapping a
	 * {@link ByteArraySection} instance for receiving the specified number of
	 * bytes.
	 */
	@Override
	public void receiveBytes( byte[] aBuffer, int aOffset, int aLength ) throws IOException {
		receiveBytesWithin( -1, aBuffer, aOffset, aLength );
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses an {@link AllocSectionDecoratorSegment} instance wrapping a
	 * {@link ByteArraySection} instance for receiving the specified number of
	 * bytes.
	 */
	@Override
	public void receiveBytesWithin( long aTimeoutMillis, byte[] aBuffer, int aOffset, int aLength ) throws IOException {
		ByteArraySection theSection = new ByteArraySection( new byte[available()] );
		AllocSectionDecoratorSegment theSegment = new AllocSectionDecoratorSegment( theSection, _transmissionMetrics );
		receiveSegmentWithin( aTimeoutMillis, theSegment );
		byte[] theBuffer = theSection.getPayload();
		System.arraycopy( theBuffer, 0, aBuffer, aOffset, aLength );

	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses an {@link AllocSectionDecoratorSegment} instance wrapping a
	 * {@link ByteArraySection} instance for receiving the given amount of
	 * bytes.
	 */
	@Override
	public Sequence receiveSequence( int aLength ) throws IOException {
		return receiveSequenceWithin( -1, aLength );
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses an {@link AllocSectionDecoratorSegment} instance wrapping a
	 * {@link ByteArraySection} instance for receiving the given amount of
	 * bytes.
	 */
	@Override
	public Sequence receiveSequenceWithin( long aTimeoutMillis, int aLength ) throws IOException {
		ByteArraySection theSection = new ByteArraySection( new byte[aLength] );
		AllocSectionDecoratorSegment theSegment = new AllocSectionDecoratorSegment( theSection, _transmissionMetrics );
		receiveSegmentWithin( aTimeoutMillis, theSegment );
		return theSection.toSequence();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  void receiveSegment( SEGMENT aSegment ) throws IOException {
		receiveSegmentWithin( -1, aSegment );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  void receiveSegmentWithin( long aTimeoutMillis, SEGMENT aSegment ) throws IOException {
		try {
			final TransmissionMessage theHandshakeMsg = aTimeoutMillis > 0 ? _inboundQueue.poll( aTimeoutMillis, TimeUnit.MILLISECONDS ) : _inboundQueue.take();
			if ( theHandshakeMsg == null ) {
				throw new TimeoutIOException( aTimeoutMillis, "Unable to retrieve a transmission within <" + aTimeoutMillis + "> milliseconds!" );
			}
			theHandshakeMsg.toPayloadSegment( aSegment );
		}
		catch ( InterruptedException e ) {
			throw new IOException( "I/O operation has unexpectedly been interrupted upon receiving a segment!", e );
		}
	}

	/**
	 * Sends a request expecting a response.
	 *
	 * @param  The {@link Segment} (sub-)type of the request.
	 * @param  the generic type
	 * @param aRequest The request to be sent.
	 * @param aResponse The response being provisioned with the response.
	 * 
	 * @throws IOException thrown in case of I/O issues while sending.
	 */
	public  void requestSegment( REQUEST aRequest, RESPONSE aResponse ) throws IOException {
		requestSegmentWithin( -1, aRequest, aResponse );
	}

	/**
	 * Sends a request expecting a response.
	 *
	 * @param  The {@link Segment} (sub-)type of the request.
	 * @param  the generic type
	 * @param aTimeoutMillis The timeout to wait for sending the request and
	 *        receiving the response till aborting.
	 * @param aRequest The request to be sent.
	 * @param aResponse The response being provisioned with the response.
	 * 
	 * @throws IOException thrown in case of I/O issues (e.g. a timeout) while
	 *         sending.
	 */
	public  void requestSegmentWithin( long aTimeoutMillis, REQUEST aRequest, RESPONSE aResponse ) throws IOException {
		requestSegmentWithin( aTimeoutMillis, new TransmissionMessage( _sequenceNumber.getAndIncrement(), TransmissionType.ACKNOWLEDGEABLE_REQUEST, aRequest, aResponse, _transmissionMetrics ) );
	}

	/**
	 * Sends a request expecting a response.
	 *
	 * @param  The {@link Segment} (sub-)type of the request.
	 * @param  the generic type
	 * @param aRequest The request to be sent.
	 * @param aResponse The response being provisioned with the response.
	 * @param isAcknowledgeable True in case an acknowledgment reply is
	 *        required.
	 * 
	 * @throws IOException thrown in case of I/O issues while sending.
	 */
	public  void requestSegment( REQUEST aRequest, RESPONSE aResponse, boolean isAcknowledgeable ) throws IOException {
		requestSegmentWithin( -1, aRequest, aResponse, isAcknowledgeable );
	}

	/**
	 * Sends a request expecting a response.
	 *
	 * @param  The {@link Segment} (sub-)type of the request.
	 * @param  the generic type
	 * @param aTimeoutMillis The timeout to wait for sending the request and
	 *        receiving the response till aborting.
	 * @param aRequest The request to be sent.
	 * @param aResponse The response being provisioned with the response.
	 * @param isAcknowledgeable True in case an acknowledgment reply is
	 *        required.
	 * 
	 * @throws IOException thrown in case of I/O issues (e.g. a timeout) while
	 *         sending.
	 */
	public  void requestSegmentWithin( long aTimeoutMillis, REQUEST aRequest, RESPONSE aResponse, boolean isAcknowledgeable ) throws IOException {
		requestSegmentWithin( aTimeoutMillis, new TransmissionMessage( _sequenceNumber.getAndIncrement(), isAcknowledgeable ? TransmissionType.ACKNOWLEDGEABLE_REQUEST : TransmissionType.REQUEST, aRequest, aResponse, _transmissionMetrics ) );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public  void transmitSegment( SEGMENT aSegment ) throws IOException {
		transmitSegmentWithin( _transmissionMetrics.getAcknowledgeTimeoutMillis(), _transmissionMetrics.getAcknowledgeRetryNumber(), new TransmissionMessage( _sequenceNumber.getAndIncrement(), TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION, aSegment, _transmissionMetrics ) );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void transmitSequence( Sequence aSequence ) throws IOException {
		transmitSegmentWithin( _transmissionMetrics.getAcknowledgeTimeoutMillis(), _transmissionMetrics.getAcknowledgeRetryNumber(), new TransmissionMessage( _sequenceNumber.getAndIncrement(), TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION, aSequence, _transmissionMetrics ) );
	}

	/**
	 * Transmits a {@link Segment} (and blocks this thread) till all it's
	 * {@link Sequence} data (as of {@link Segment#toSequence()}) has been sent.
	 *
	 * @param  The {@link Segment} type describing the {@link Segment}
	 *        subclass used.
	 * @param aTimeoutMillis The timeout to wait for sending the request and
	 *        receiving the response till aborting.
	 * @param aRetryNumber The number of retries each of the given timeout in
	 *        milliseconds.
	 * @param aSegment The {@link Segment}'s data to be sent.
	 * 
	 * @throws IOException thrown in case of I/O issues (e.g. a timeout) while
	 *         sending.
	 */
	public  void transmitSegmentWithin( long aTimeoutMillis, int aRetryNumber, SEGMENT aSegment ) throws IOException {
		transmitSegmentWithin( aTimeoutMillis, aRetryNumber, new TransmissionMessage( _sequenceNumber.getAndIncrement(), TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION, aSegment, _transmissionMetrics ) );
	}

	/**
	 * Transmits a {@link Segment} (and blocks this thread) till all it's
	 * {@link Sequence} data (as of {@link Segment#toSequence()}) has been sent.
	 *
	 * @param  The {@link Segment} type describing the {@link Segment}
	 *        subclass used.
	 * @param aTimeoutMillis The timeout to wait for sending the request and
	 *        receiving the response till aborting.
	 * @param aSegment The {@link Segment}'s data to be sent.
	 * 
	 * @throws IOException thrown in case of I/O issues (e.g. a timeout) while
	 *         sending.
	 */
	public  void transmitSegmentWithin( long aTimeoutMillis, SEGMENT aSegment ) throws IOException {
		transmitSegmentWithin( aTimeoutMillis, 1, new TransmissionMessage( _sequenceNumber.getAndIncrement(), TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION, aSegment, _transmissionMetrics ) );
	}

	/**
	 * Transmits a {@link Sequence} (and blocks this thread) till all it's data
	 * (as of {@link Segment#toSequence()}) has been sent.
	 *
	 * @param aTimeoutMillis The timeout to wait for sending the request and
	 *        receiving the response till aborting.
	 * @param aRetryNumber The number of retries each of the given timeout in
	 *        milliseconds.
	 * @param aSequence The {@link Sequence} containing the data to be send.
	 * 
	 * @throws IOException thrown in case of I/O issues (e.g. a timeout) while
	 *         sending.
	 */
	public void transmitSequenceWithin( long aTimeoutMillis, int aRetryNumber, Sequence aSequence ) throws IOException {
		transmitSegmentWithin( aTimeoutMillis, aRetryNumber, new TransmissionMessage( _sequenceNumber.getAndIncrement(), TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION, aSequence, _transmissionMetrics ) );
	}

	/**
	 * Transmits a {@link Sequence} (and blocks this thread) till all it's data
	 * (as of {@link Segment#toSequence()}) has been sent.
	 *
	 * @param aTimeoutMillis The timeout to wait for sending the request and
	 *        receiving the response till aborting.
	 * @param aSequence The {@link Sequence} containing the data to be send.
	 * 
	 * @throws IOException thrown in case of I/O issues (e.g. a timeout) while
	 *         sending.
	 */
	public void transmitSequenceWithin( long aTimeoutMillis, Sequence aSequence ) throws IOException {
		transmitSegmentWithin( aTimeoutMillis, 1, new TransmissionMessage( _sequenceNumber.getAndIncrement(), TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION, aSequence, _transmissionMetrics ) );
	}

	/**
	 * Transmits a {@link Segment} (and blocks this thread) till all it's
	 * {@link Sequence} data (as of {@link Segment#toSequence()}) has been sent.
	 * 
	 * @param  The {@link Segment} type describing the {@link Segment}
	 *        subclass used.
	 * @param aSegment The {@link Segment}'s data to be sent.
	 * 
	 * @param isAcknowledgeable True in case an acknowledgment reply is
	 *        required.
	 * 
	 * @throws IOException thrown in case of I/O issues (e.g. a timeout) while
	 *         sending.
	 */
	public  void transmitSegment( SEGMENT aSegment, boolean isAcknowledgeable ) throws IOException {
		transmitSegmentWithin( _transmissionMetrics.getAcknowledgeTimeoutMillis(), _transmissionMetrics.getAcknowledgeRetryNumber(), new TransmissionMessage( _sequenceNumber.getAndIncrement(), isAcknowledgeable ? TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION : TransmissionType.TRANSMISSION, aSegment, _transmissionMetrics ) );
	}

	/**
	 * Transmits a {@link Sequence} (and blocks this thread) till all it's data
	 * (as of {@link Segment#toSequence()}) has been sent.
	 * 
	 * @param aSequence The {@link Sequence} containing the data to be send.
	 * 
	 * @param isAcknowledgeable True in case an acknowledgment reply is
	 *        required.
	 * 
	 * @throws IOException thrown in case of I/O issues (e.g. a timeout) while
	 *         sending.
	 */
	public void transmitSequence( Sequence aSequence, boolean isAcknowledgeable ) throws IOException {
		transmitSegmentWithin( _transmissionMetrics.getAcknowledgeTimeoutMillis(), _transmissionMetrics.getAcknowledgeRetryNumber(), new TransmissionMessage( _sequenceNumber.getAndIncrement(), isAcknowledgeable ? TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION : TransmissionType.TRANSMISSION, aSequence, _transmissionMetrics ) );
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses a {@link ByteSegment} instance for wrapping up the transmission of a
	 * single byte.
	 */
	@Override
	public void transmitByte( byte aByte ) throws IOException {
		ByteSegment theSegment = new ByteSegment( aByte );
		transmitSegment( theSegment );
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses an {@link AllocSectionDecoratorSegment} instance wrapping a
	 * {@link ByteArraySection} instance for receiving all currently available
	 * (as of {@link #available()}) bytes.
	 */
	@Override
	public void transmitBytes( byte[] aBytes ) throws IOException {
		ByteArraySection theSection = new ByteArraySection( aBytes );
		AllocSectionDecoratorSegment theSegment = new AllocSectionDecoratorSegment( theSection, _transmissionMetrics );
		transmitSegment( theSegment );
	}

	/**
	 * {@inheritDoc}
	 * 
	 * Uses an {@link AllocSectionDecoratorSegment} instance wrapping a
	 * {@link ByteArraySection} instance for receiving the number of specified
	 * bytes.
	 */
	@Override
	public void transmitBytes( byte[] aBytes, int aOffset, int aLength ) throws IOException {
		byte[] theBuffer = new byte[aLength];
		System.arraycopy( aBytes, aOffset, theBuffer, 0, aLength );
		ByteArraySection theSection = new ByteArraySection( theBuffer );
		AllocSectionDecoratorSegment theSegment = new AllocSectionDecoratorSegment( theSection, _transmissionMetrics );
		transmitSegment( theSegment );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public HandshakePortController withOpen() throws IOException {
		open();
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public HandshakePortController withOpen( PM aPortMetrics ) throws IOException {
		open( aPortMetrics );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public HandshakePortController withOpenUnchecked( PM aPortMetrics ) {
		openUnchecked( aPortMetrics );
		return this;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public HandshakePortController withOpenUnchecked() {
		openUnchecked();
		return this;
	}

	/**
	 * Creates builder to build {@link HandshakePortController}.
	 *
	 * @param  The actual {@link PortMetrics} type to use.
	 * 
	 * @return The accordingly created builder.
	 */
	public static  Builder builder() {
		return new Builder<>();
	}

	// /////////////////////////////////////////////////////////////////////////
	// HELPER:
	// /////////////////////////////////////////////////////////////////////////

	private void start() {
		_executorService.execute( new OutboundQueueDaemon() );
		_executorService.execute( new InboundQueueDaemon() );
		_executorService.execute( new RequestQueueDaemon() );
		_executorService.execute( new ConsumerQueueDaemon() );
	}

	private void transmitSegmentWithin( long aTimeoutMillis, int aRetryNumber, TransmissionMessage aTransmissionMessage ) throws IOException {

		aRetryNumber = aRetryNumber != -1 ? aRetryNumber : _transmissionMetrics.getAcknowledgeRetryNumber();
		aTimeoutMillis = aTimeoutMillis != -1 ? aTimeoutMillis : _transmissionMetrics.getAcknowledgeTimeoutMillis();

		if ( aTransmissionMessage.getTransmissionType().isAcknowledgeable() ) {
			final int theSequenceNumber = aTransmissionMessage.getSequenceNumber();
			for ( int i = 0; i < aRetryNumber; i++ ) {
				if ( !_outboundQueue.contains( aTransmissionMessage ) ) {
					_outboundQueue.offer( aTransmissionMessage );
				}
				try {
					synchronized ( aTransmissionMessage ) {
						aTransmissionMessage.wait( aTimeoutMillis );
					}
				}
				catch ( InterruptedException interrupted ) {}

				if ( aTransmissionMessage.getException() != null ) {
					_outboundQueue.remove( aTransmissionMessage );
					_sequenceNumToAcknowledge.remove( theSequenceNumber );
					throw aTransmissionMessage.getException();
				}
				else if ( aTransmissionMessage.hasAcknowledge() ) {
					_sequenceNumToAcknowledge.remove( theSequenceNumber );
					_outboundQueue.remove( aTransmissionMessage );
					return;
				}
			}
			_outboundQueue.remove( aTransmissionMessage );
			_sequenceNumToAcknowledge.remove( theSequenceNumber );
			throw new TimeoutIOException( _transmissionMetrics.getAcknowledgeTimeoutMillis(), "Aborting transmission after <" + aRetryNumber + "> retries without an acknowledge with timeouts each of <" + _transmissionMetrics.getAcknowledgeTimeoutMillis() + "> milliseconds duration! Failed transmission: " + ( aTransmissionMessage != null && aTransmissionMessage.getPayload() != null ? " Failed transmission: " + aTransmissionMessage.getPayload().toString() : "" ) );
		}
		else {
			for ( int i = 0; i < aRetryNumber; i++ ) {
				if ( !_outboundQueue.contains( aTransmissionMessage ) ) {
					_outboundQueue.offer( aTransmissionMessage );
				}
				try {
					synchronized ( aTransmissionMessage ) {
						aTransmissionMessage.wait( aTimeoutMillis );
					}
				}
				catch ( InterruptedException interrupted ) {}

				if ( aTransmissionMessage.getException() != null ) {
					_outboundQueue.remove( aTransmissionMessage );
					throw aTransmissionMessage.getException();
				}
			}
			_outboundQueue.remove( aTransmissionMessage );
		}
	}

	private  void requestSegmentWithin( long aTimeoutMillis, TransmissionMessage aRequestMsg ) throws IOException {
		final int theSequenceNumber = aRequestMsg.getSequenceNumber();
		for ( int i = 0; i < _transmissionMetrics.getReplyRetryNumber(); i++ ) {
			if ( !_outboundQueue.contains( aRequestMsg ) ) {
				_outboundQueue.offer( aRequestMsg );
			}
			try {
				synchronized ( aRequestMsg ) {
					aRequestMsg.wait( aTimeoutMillis != -1 ? aTimeoutMillis : _transmissionMetrics.getReplyTimeoutMillis() );
				}
			}
			catch ( InterruptedException interrupted ) {}

			if ( aRequestMsg.getException() != null ) {
				_sequenceNumToRequest.remove( theSequenceNumber );
				_outboundQueue.remove( aRequestMsg );
				throw aRequestMsg.getException();
			}
			else if ( aRequestMsg.hasResponse() ) {
				_sequenceNumToRequest.remove( theSequenceNumber );
				_outboundQueue.remove( aRequestMsg );
				return;
			}
		}
		_sequenceNumToRequest.remove( theSequenceNumber );
		_outboundQueue.remove( aRequestMsg );
		throw new TimeoutIOException( _transmissionMetrics.getReplyTimeoutMillis(), "Aborting transmission after <" + _transmissionMetrics.getReplyRetryNumber() + "> retries without an acknowledge with timeouts each of <" + _transmissionMetrics.getReplyTimeoutMillis() + "> milliseconds duration! Failed transmission: " + aRequestMsg.getPayload().toString() );
	}

	private void offerInbound( TransmissionMessage aTransmissionMsg ) {
		if ( !_inboundQueue.offer( aTransmissionMsg ) ) {
			if ( aTransmissionMsg.getTransmissionType().isAcknowledgeable() ) {
				_outboundQueue.offer( new AcknowledgeMessage( AcknowledgeType.TRANSMISSION_DISMISSED, aTransmissionMsg.getSequenceNumber(), _transmissionMetrics ) );
			}
			LOGGER.log( Level.WARNING, "Skipping inbound transmission for session ID <" + aTransmissionMsg.getSequenceNumber() + "> as the queue capacity has been exceeded." );
		}
		else {
			if ( aTransmissionMsg.getTransmissionType().isAcknowledgeable() ) {
				_outboundQueue.offer( new AcknowledgeMessage( AcknowledgeType.ACKNOWLEDGE, aTransmissionMsg.getSequenceNumber(), _transmissionMetrics ) );
			}
		}
	}

	private boolean addSequenceNumber( TransmissionMessage eTransmissionMsg ) {
		if ( !_sequenceNumbers.contains( eTransmissionMsg.getSequenceNumber() ) ) {
			synchronized ( _sequenceNumbers ) {
				if ( !_sequenceNumbers.contains( eTransmissionMsg.getSequenceNumber() ) ) {
					_sequenceNumbers.add( eTransmissionMsg.getSequenceNumber() );
					if ( _sequenceNumbers.size() > MAX_SEQUENCE_NUMBER_COUNT ) {
						_sequenceNumbers.remove( 0 );
					}
					return true;
				}
			}
		}
		return false;
	}

	// /////////////////////////////////////////////////////////////////////////
	// INNER CLASSES:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Builder for building {@link HandshakePortController} instances.
	 * 
	 * @param  The actual {@link PortMetrics} type to use.
	 */
	public static final class Builder implements AcknowledgeTimeoutMillisBuilder>, AcknowledgeRetryNumberBuilder>, ReplyTimeoutMillisBuilder>, ReplyRetryNumberBuilder>, CrcAlgorithmBuilder>, ChecksumValidationModeBuilder>, EndianessBuilder>, SequenceNumberInitValueBuilder>, SequenceNumberWidthBuilder> {

		private int acknowledgeRetryNumber;
		private long acknowledgeTimeoutInMs;
		private int replyRetryNumber;
		private long replyTimeoutInMs;
		private CrcAlgorithm crcAlgorithm;
		private ChecksumValidationMode checksumValidationMode;
		private Endianess endianess;
		private ExecutorService executorService;
		private Port port;
		private int sequenceNumberInitValue;
		private int sequenceNumberWidth;
		private int inboundQueueCapacity;

		private Builder() {}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Builder withReplyRetryNumber( int aReplyRetryNumber ) {
			replyRetryNumber = aReplyRetryNumber;
			return this;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Builder withReplyTimeoutMillis( long aReplyTimeoutInMs ) {
			replyTimeoutInMs = aReplyTimeoutInMs;
			return this;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Builder withAcknowledgeRetryNumber( int aAcknowledgeRetryNumber ) {
			acknowledgeRetryNumber = aAcknowledgeRetryNumber;
			return this;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Builder withAcknowledgeTimeoutMillis( long aAcknowledgeTimeoutInMs ) {
			acknowledgeTimeoutInMs = aAcknowledgeTimeoutInMs;
			return this;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Builder withCrcAlgorithm( CrcAlgorithm aCrcAlgorithm ) {
			crcAlgorithm = aCrcAlgorithm;
			return this;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Builder withChecksumValidationMode( ChecksumValidationMode aChecksumValidationMode ) {
			checksumValidationMode = aChecksumValidationMode;
			return this;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Builder withEndianess( Endianess aEndianess ) {
			endianess = aEndianess;
			return this;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Builder withSequenceNumberInitValue( int aSequenceNumberInitValue ) {
			sequenceNumberInitValue = aSequenceNumberInitValue;
			return this;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public Builder withSequenceNumberWidth( int aSequenceNumberWidth ) {
			sequenceNumberWidth = aSequenceNumberWidth;
			return this;
		}

		/**
		 * Sets the queue capacity of unprocessed inbound messages.
		 * 
		 * @param aInboundQueueCapacity The capacity of the inbound queue, any
		 *        exceeding inbound transmissions are skipped.
		 * 
		 * @return The {@link Builder} to chain other operations as of the
		 *         builder pattern.
		 */
		public Builder withInboundQueueCapacity( int aInboundQueueCapacity ) {
			inboundQueueCapacity = aInboundQueueCapacity;
			return this;
		}

		/**
		 * Sets the according property for configuring the
		 * {@link HandshakePortController} upon invoking {@link #build()}.
		 *
		 * @param aExecutorService The {@link ExecutorService} to be used when
		 *        creating {@link Thread} instances for handling input and
		 *        output data simultaneously.
		 * 
		 * @return The {@link Builder} to chain other operations as of the
		 *         builder pattern.
		 */
		public Builder withExecutorService( ExecutorService aExecutorService ) {
			executorService = aExecutorService;
			return this;
		}

		/**
		 * Sets the according property for configuring the
		 * {@link HandshakePortController} upon invoking {@link #build()}.
		 *
		 * @param aPort the a port
		 * 
		 * @return The {@link Builder} to chain other operations as of the
		 *         builder pattern.
		 */
		public Builder withPort( Port aPort ) {
			port = aPort;
			return this;
		}

		/**
		 * Builds the.
		 *
		 * @return the full duplex segment multiplexer
		 */
		public HandshakePortController build() {
			return new HandshakePortController<>( this );
		}
	}

	private class InboundQueueDaemon implements Runnable {

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void run() {
			TransmissionMessage ePingMsg;
			AcknowledgeMessage ePongAck;
			TransmissionMessage eTransmissionMsg;
			TransmissionMessage eRequestMsg;
			TransmissionMessage eResponseMsg = null;
			TransmissionMessage eAcknowledgeableTransmissionMsg;
			AcknowledgeMessage eAcknowledgeableTransmissionAck;
			AcknowledgeMessage eAcknowledgeableTransmissionDismissedAck;
			TransmissionMessage eAcknowledgeableRequestMsg;
			TransmissionMessage eAcknowledgeableResponseMsg;
			AcknowledgeMessage eAcknowledgeableResponseAck;
			AcknowledgeMessage eAcknowledgeableRequestDismissedAck;
			MagicBytesSegmentMultiplexer eMultiplexer;

			while ( !isClosed() ) {
				try {
					// @formatter:off
					eMultiplexer = new MagicBytesSegmentMultiplexer(
						ePingMsg = new TransmissionMessage( TransmissionType.PING, _transmissionMetrics ),
						eTransmissionMsg = new TransmissionMessage( TransmissionType.TRANSMISSION, _transmissionMetrics ),
						eAcknowledgeableTransmissionMsg = new TransmissionMessage( TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION, _transmissionMetrics ),
						eRequestMsg = new TransmissionMessage(TransmissionType.REQUEST, _transmissionMetrics ),
						eResponseMsg = new TransmissionMessage( TransmissionType.RESPONSE, _transmissionMetrics ),
						eAcknowledgeableRequestMsg = new TransmissionMessage(TransmissionType.ACKNOWLEDGEABLE_REQUEST, _transmissionMetrics ), 
						eAcknowledgeableResponseMsg = new TransmissionMessage( TransmissionType.ACKNOWLEDGEABLE_RESPONSE, _transmissionMetrics ), 
						ePongAck = new AcknowledgeMessage( AcknowledgeType.PONG, _transmissionMetrics ),
						eAcknowledgeableTransmissionAck = new AcknowledgeMessage( AcknowledgeType.ACKNOWLEDGE, _transmissionMetrics ),
						eAcknowledgeableTransmissionDismissedAck = new AcknowledgeMessage( AcknowledgeType.TRANSMISSION_DISMISSED, _transmissionMetrics ),
						eAcknowledgeableResponseAck = new AcknowledgeMessage( AcknowledgeType.RESPONSE, _transmissionMetrics ),
						eAcknowledgeableRequestDismissedAck= new AcknowledgeMessage( AcknowledgeType.REQUEST_DISMISSED, _transmissionMetrics )
					);
					// @formatter:on

					_port.receiveSegment( eMultiplexer );

					// PING_MSG:
					if ( eMultiplexer.getCallee() == ePingMsg ) {
						onPingMsg( ePingMsg );
					}
					// PONG_ACK:
					else if ( eMultiplexer.getCallee() == ePongAck ) {
						onPongAck( ePongAck );
					}
					// TRANSMISSION_MSG:
					else if ( eMultiplexer.getCallee() == eTransmissionMsg ) {
						onTransmissionMsg( eTransmissionMsg );
					}
					// ACKNOWLEDGEABLE_TRANSMISSION_MSG:
					else if ( eMultiplexer.getCallee() == eAcknowledgeableTransmissionMsg ) {
						onAcknowledgeableTransmissionMsg( eAcknowledgeableTransmissionMsg );
					}
					// TRANSMISSION_ACK:
					else if ( eMultiplexer.getCallee() == eAcknowledgeableTransmissionAck ) {
						onAcknowledgeTransmissionAck( eAcknowledgeableTransmissionAck );
					}
					// TRANSMISSION_DISMISSED_ACK:
					else if ( eMultiplexer.getCallee() == eAcknowledgeableTransmissionDismissedAck ) {
						onAcknowledgeableTransmissionDismissedAck( eAcknowledgeableTransmissionDismissedAck );
					}
					// ACKNOWLEDGEABLE_REQUEST_MSG:
					else if ( eMultiplexer.getCallee() == eAcknowledgeableRequestMsg ) {
						onAcknowledgeableRequestMsg( eAcknowledgeableRequestMsg );
					}
					// ACKNOWLEDGEABLE_RESPONSE_MSG:
					else if ( eMultiplexer.getCallee() == eAcknowledgeableResponseMsg ) {
						onAcknowledgeableResponseMsg( eAcknowledgeableResponseMsg );
					}
					// ACLNOWLEDGEABLE_REQUEST_DISMISSED_ACK:
					else if ( eMultiplexer.getCallee() == eAcknowledgeableRequestDismissedAck ) {
						onAcknowledgeableRequestDismissedAck( eAcknowledgeableRequestDismissedAck );
					}
					// ACKNOWLEDGEBALE_RESPONSE_ACK:
					else if ( eMultiplexer.getCallee() == eAcknowledgeableResponseAck ) {
						onAcknowledgeableResponseAck( eAcknowledgeableResponseAck );
					}
					// REQUEST_MSG:
					else if ( eMultiplexer.getCallee() == eRequestMsg ) {
						onRequestMsg( eRequestMsg );
					}
					// RESPONSE_MSG:
					else if ( eMultiplexer.getCallee() == eResponseMsg ) {
						onResponseMsg( eResponseMsg );
					}
				}
				catch ( IOException e ) {
					if ( !isClosed() ) {
						try {
							if ( _port.available() > 0 ) {
								LOGGER.log( Level.WARNING, Trap.asMessage( e ), e );
								// Cleanup buffer, try to get back to sync |-->
								_port.skipAvailableWithin( IoRetryCount.MIN.getValue(), IoSleepLoopTime.MIN.getTimeMillis() );
								//	for ( int i = 0; i < IoRetryCount.MIN.getValue(); i++ ) {
								//		try {
								//			Thread.sleep( IoSleepLoopTime.MIN.getTimeInMs() );
								//		}
								//		catch ( InterruptedException ignore ) {}
								//		_port.skipAvailable();
								//	}
								// Cleanup buffer, try to get back to sync <--| 
							}
						}
						catch ( IOException ignore ) {}
					}
				}
			}
		}

		private void onTransmissionMsg( TransmissionMessage eTransmissionMsg ) {
			if ( !_segmentConsumerTupels.isEmpty() ) {
				_consumerQueue.offer( eTransmissionMsg );
			}
			else {
				offerInbound( eTransmissionMsg );
			}
		}

		private void onRequestMsg( TransmissionMessage aRequestMsg ) {
			if ( addSequenceNumber( aRequestMsg ) ) {
				_requestQueue.offer( aRequestMsg );
			}
		}

		private void onResponseMsg( TransmissionMessage aResponseMsg ) throws TransmissionException {
			final TransmissionMessage theRequestMsg = _sequenceNumToRequest.remove( aResponseMsg.getSequenceNumber() );
			if ( theRequestMsg != null ) {
				theRequestMsg.setResponse( aResponseMsg.getPayload().toSequence() );
				synchronized ( theRequestMsg ) {
					theRequestMsg.notifyAll();
				}
			}
		}

		private void onAcknowledgeableResponseAck( AcknowledgeMessage aAcknowledgeableResponseAck ) {
			final TransmissionMessage theAcknowledgeableResponseMsg = _sequenceNumToAcknowledge.remove( aAcknowledgeableResponseAck.getSequenceNumber() );
			if ( aAcknowledgeableResponseAck != null ) {
				theAcknowledgeableResponseMsg.acknowledge();
				synchronized ( theAcknowledgeableResponseMsg ) {
					theAcknowledgeableResponseMsg.notifyAll();
				}
			}
		}

		private void onAcknowledgeableRequestDismissedAck( AcknowledgeMessage aAcknowledgeableRequestDismissedAck ) {
			final TransmissionMessage theRequestMsg = _sequenceNumToRequest.remove( aAcknowledgeableRequestDismissedAck.getSequenceNumber() );
			if ( theRequestMsg != null ) {
				theRequestMsg.setException( new IOException( new IllegalArgumentException( "Bad request, no remote <" + RequestHandler.class.getSimpleName() + "> has been found for given request <" + theRequestMsg.getPayload() + ">!" ) ) );
				synchronized ( theRequestMsg ) {
					theRequestMsg.notifyAll();
				}
			}
		}

		private void onAcknowledgeableResponseMsg( TransmissionMessage aAcknowledgeableResponseMsg ) throws TransmissionException {
			final TransmissionMessage theRequestMsg = _sequenceNumToRequest.remove( aAcknowledgeableResponseMsg.getSequenceNumber() );
			if ( theRequestMsg != null ) {
				theRequestMsg.setResponse( aAcknowledgeableResponseMsg.getPayload().toSequence() );
				synchronized ( theRequestMsg ) {
					theRequestMsg.notifyAll();
				}
				_outboundQueue.offer( new AcknowledgeMessage( AcknowledgeType.RESPONSE, aAcknowledgeableResponseMsg.getSequenceNumber(), _transmissionMetrics ) );
			}
		}

		private void onAcknowledgeableRequestMsg( TransmissionMessage aAcknowledgeableRequestMsg ) {
			if ( addSequenceNumber( aAcknowledgeableRequestMsg ) ) {
				_requestQueue.offer( aAcknowledgeableRequestMsg );
			}
		}

		private void onAcknowledgeableTransmissionDismissedAck( AcknowledgeMessage aAcknowledgeableTransmissionDismissedAck ) {
			final TransmissionMessage theAcknowledgeableTransmissionMsg = _sequenceNumToAcknowledge.remove( aAcknowledgeableTransmissionDismissedAck.getSequenceNumber() );
			if ( theAcknowledgeableTransmissionMsg != null ) {
				theAcknowledgeableTransmissionMsg.setException( new IOException( "Receiver dismissed transmission with sequence number <" + aAcknowledgeableTransmissionDismissedAck.getSequenceNumber() + ">!" ) );
				synchronized ( theAcknowledgeableTransmissionMsg ) {
					theAcknowledgeableTransmissionMsg.notifyAll();
				}
			}
		}

		private void onAcknowledgeTransmissionAck( AcknowledgeMessage aAcknowledgeTransmissionAck ) {
			final TransmissionMessage theAcknowledgeableTransmissionMsg = _sequenceNumToAcknowledge.remove( aAcknowledgeTransmissionAck.getSequenceNumber() );
			if ( theAcknowledgeableTransmissionMsg != null ) {
				theAcknowledgeableTransmissionMsg.acknowledge();
				synchronized ( theAcknowledgeableTransmissionMsg ) {
					theAcknowledgeableTransmissionMsg.notifyAll();
				}
			}
		}

		private void onAcknowledgeableTransmissionMsg( TransmissionMessage aAcknowledgeableTransmissionMsg ) {
			if ( addSequenceNumber( aAcknowledgeableTransmissionMsg ) ) {
				onTransmissionMsg( aAcknowledgeableTransmissionMsg );
				_outboundQueue.offer( new AcknowledgeMessage( AcknowledgeType.ACKNOWLEDGE, aAcknowledgeableTransmissionMsg.getSequenceNumber(), _transmissionMetrics ) );
			}
		}

		private void onPingMsg( TransmissionMessage aPingMsg ) {
			if ( addSequenceNumber( aPingMsg ) ) {
				_outboundQueue.offer( new AcknowledgeMessage( AcknowledgeType.PONG, aPingMsg.getSequenceNumber(), _transmissionMetrics ) );
				if ( _pingHandler != null ) {
					_pingHandler.run();
				}
			}
		}

		private void onPongAck( AcknowledgeMessage aPongAck ) {
			final TransmissionMessage thePingMsg = _sequenceNumToAcknowledge.remove( aPongAck.getSequenceNumber() );
			if ( thePingMsg != null ) {
				thePingMsg.acknowledge();
				synchronized ( thePingMsg ) {
					thePingMsg.notifyAll();
				}
			}
		}
	}

	private class ConsumerQueueDaemon implements Runnable {

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void run() {
			TransmissionMessage eConsumerMsg;
			while ( !isClosed() ) {
				try {
					eConsumerMsg = _consumerQueue.take();
					try {
						onSegment( eConsumerMsg );
						if ( eConsumerMsg.getTransmissionType().isAcknowledgeable() ) {
							_outboundQueue.offer( new AcknowledgeMessage( AcknowledgeType.ACKNOWLEDGE, eConsumerMsg.getSequenceNumber(), _transmissionMetrics ) );
						}
					}
					catch ( IOException | IllegalArgumentException e ) {
						offerInbound( eConsumerMsg );
						LOGGER.log( Level.WARNING, Trap.asMessage( e ), e );
					}
				}
				catch ( InterruptedException ignore ) {}
			}
		}

		private void onSegment( TransmissionMessage aConsumerMsg ) throws IOException {
			final Sequence theSequence = aConsumerMsg.getPayload().toSequence();
			IOException theCause = null;
			for ( SegmentConsumerTupel eSegmentConsumerTupel : _segmentConsumerTupels ) {
				try {
					eSegmentConsumerTupel.segment.fromTransmission( theSequence );
					eSegmentConsumerTupel.onSegment();
					return;
				}
				catch ( IOException e ) {
					theCause = theCause == null ? e : theCause;
				}
			}
			throw new IllegalArgumentException( "Bad transmission, no <" + SegmentConsumer.class.getSimpleName() + "> has been found!" + ( theCause != null ? " Cause: " + theCause.getMessage() : "" ), theCause );
		}
	}

	private class RequestQueueDaemon implements Runnable {

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void run() {
			TransmissionMessage eRequestMsg;
			TransmissionMessage eResponseMsg;
			while ( !isClosed() ) {
				try {
					eRequestMsg = _requestQueue.take();
					try {
						eResponseMsg = new TransmissionMessage( eRequestMsg.getSequenceNumber(), eRequestMsg.getTransmissionType().isAcknowledgeable() ? TransmissionType.ACKNOWLEDGEABLE_RESPONSE : TransmissionType.RESPONSE, onRequest( eRequestMsg ), _transmissionMetrics );
						transmitSegmentWithin( _transmissionMetrics.getAcknowledgeTimeoutMillis(), _transmissionMetrics.getAcknowledgeRetryNumber(), eResponseMsg );
					}
					catch ( IOException | IllegalArgumentException e ) {
						LOGGER.log( Level.WARNING, Trap.asMessage( e ), e );
					}
				}
				catch ( InterruptedException ignore ) {}
			}
		}

		private Segment onRequest( TransmissionMessage aRequestMsg ) throws IOException {
			final Sequence theSequence = aRequestMsg.getPayload().toSequence();
			IOException theCause = null;
			for ( RequestHandlerTupel eRequestHandlerTupel : _requestHandlerTupels ) {
				try {
					eRequestHandlerTupel.request.fromTransmission( theSequence );
					return eRequestHandlerTupel.onRequest();
				}
				catch ( IOException e ) {
					theCause = theCause == null ? e : theCause;
				}
			}
			_outboundQueue.offer( new AcknowledgeMessage( AcknowledgeType.REQUEST_DISMISSED, aRequestMsg.getSequenceNumber() ) );
			throw new IllegalArgumentException( "Bad request, no <" + RequestHandler.class.getSimpleName() + "> has been found!" + ( theCause != null ? " Cause: " + theCause.getMessage() : "" ), theCause );
		}
	}

	private class OutboundQueueDaemon implements Runnable {

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void run() {
			Message eOut;
			while ( !isClosed() ) {
				try {
					eOut = _outboundQueue.take();
					// PING:
					if ( eOut instanceof TransmissionMessage && ( (TransmissionMessage) eOut ).getTransmissionType() == TransmissionType.PING ) {
						onPingMsg( (TransmissionMessage) eOut );
					}
					// TRANSMISSION:
					else if ( eOut instanceof TransmissionMessage && ( (TransmissionMessage) eOut ).getTransmissionType() == TransmissionType.TRANSMISSION ) {
						onTransmissionMsg( (TransmissionMessage) eOut );
					}
					// REQUEST:
					else if ( eOut instanceof TransmissionMessage && ( (TransmissionMessage) eOut ).getTransmissionType() == TransmissionType.REQUEST ) {
						onRequestMsg( (TransmissionMessage) eOut );
					}
					// RESPONSE:
					else if ( eOut instanceof TransmissionMessage && ( (TransmissionMessage) eOut ).getTransmissionType() == TransmissionType.RESPONSE ) {
						onResponseMsg( (TransmissionMessage) eOut );
					}
					//ACKNOWLEDGEABLE_TRANSMISSION:
					else if ( eOut instanceof TransmissionMessage && ( (TransmissionMessage) eOut ).getTransmissionType() == TransmissionType.ACKNOWLEDGEABLE_TRANSMISSION ) {
						onAcknowledgeableTransmissionMsg( (TransmissionMessage) eOut );
					}
					// ACKNOWLEDGEABLE_REQUEST:
					else if ( eOut instanceof TransmissionMessage && ( (TransmissionMessage) eOut ).getTransmissionType() == TransmissionType.ACKNOWLEDGEABLE_REQUEST ) {
						onAcknowledgeableRequestMsg( (TransmissionMessage) eOut );
					}
					// ACKNOWLEDGEABLE_RESPONSE:
					else if ( eOut instanceof TransmissionMessage && ( (TransmissionMessage) eOut ).getTransmissionType() == TransmissionType.ACKNOWLEDGEABLE_RESPONSE ) {
						onAcknowledgeableResponseMsg( (TransmissionMessage) eOut );
					}
					// ACKNOWLEDGE:
					else {
						onAcknowledge( eOut );
					}
				}
				catch ( InterruptedException e ) { /* Probably closed */ }
			}
		}

		private void onAcknowledge( Message aAcknowledge ) {
			try {
				_port.transmitSegment( aAcknowledge );
			}
			catch ( IOException e ) {
				LOGGER.log( Level.WARNING, Trap.asMessage( e ), e );
			}
		}

		private void onAcknowledgeableResponseMsg( TransmissionMessage aAcknowledgeableResponseMsg ) {
			_sequenceNumToAcknowledge.put( aAcknowledgeableResponseMsg.getSequenceNumber(), aAcknowledgeableResponseMsg );
			try {
				_port.transmitSegment( aAcknowledgeableResponseMsg );
			}
			catch ( IOException e ) {
				_sequenceNumToAcknowledge.remove( aAcknowledgeableResponseMsg.getSequenceNumber() );
				aAcknowledgeableResponseMsg.setException( e );
				synchronized ( aAcknowledgeableResponseMsg ) {
					aAcknowledgeableResponseMsg.notifyAll();
				}
			}
		}

		private void onAcknowledgeableRequestMsg( TransmissionMessage aAcknowledgeableRequestMsg ) {
			_sequenceNumToRequest.put( aAcknowledgeableRequestMsg.getSequenceNumber(), aAcknowledgeableRequestMsg );
			try {
				_port.transmitSegment( aAcknowledgeableRequestMsg );
			}
			catch ( IOException e ) {
				_sequenceNumToRequest.remove( aAcknowledgeableRequestMsg.getSequenceNumber() );
				aAcknowledgeableRequestMsg.setException( e );
				synchronized ( aAcknowledgeableRequestMsg ) {
					aAcknowledgeableRequestMsg.notifyAll();
				}
			}
		}

		private void onAcknowledgeableTransmissionMsg( TransmissionMessage aAcknowledgeableTransmissionMsg ) {
			_sequenceNumToAcknowledge.put( aAcknowledgeableTransmissionMsg.getSequenceNumber(), aAcknowledgeableTransmissionMsg );
			try {
				_port.transmitSegment( aAcknowledgeableTransmissionMsg );
			}
			catch ( IOException e ) {
				_sequenceNumToAcknowledge.remove( aAcknowledgeableTransmissionMsg.getSequenceNumber() );
				aAcknowledgeableTransmissionMsg.setException( e );
				synchronized ( aAcknowledgeableTransmissionMsg ) {
					aAcknowledgeableTransmissionMsg.notifyAll();
				}
			}
		}

		private void onTransmissionMsg( TransmissionMessage aTransmissionMsg ) {
			try {
				_port.transmitSegment( aTransmissionMsg );
			}
			catch ( IOException e ) {
				aTransmissionMsg.setException( e );
			}
			synchronized ( aTransmissionMsg ) {
				aTransmissionMsg.notifyAll();
			}
		}

		private void onRequestMsg( TransmissionMessage aRequestMsg ) {
			_sequenceNumToRequest.put( aRequestMsg.getSequenceNumber(), aRequestMsg );
			try {
				_port.transmitSegment( aRequestMsg );
			}
			catch ( IOException e ) {
				_sequenceNumToRequest.remove( aRequestMsg.getSequenceNumber() );
				aRequestMsg.setException( e );
				synchronized ( aRequestMsg ) {
					aRequestMsg.notifyAll();
				}
			}
		}

		private void onResponseMsg( TransmissionMessage aResponseMsg ) {
			try {
				_port.transmitSegment( aResponseMsg );
			}
			catch ( IOException e ) {
				aResponseMsg.setException( e );
			}
			synchronized ( aResponseMsg ) {
				aResponseMsg.notifyAll();
			}
		}

		private void onPingMsg( TransmissionMessage aPingMsg ) {
			_sequenceNumToAcknowledge.put( aPingMsg.getSequenceNumber(), aPingMsg );
			try {
				_port.transmitSegment( aPingMsg );
			}
			catch ( IOException e ) {
				_sequenceNumToAcknowledge.remove( aPingMsg.getSequenceNumber() );
				aPingMsg.setException( e );
				synchronized ( aPingMsg ) {
					aPingMsg.notifyAll();
				}
			}
		}
	}

	private static class SegmentConsumerTupel {

		SEGMENT segment;
		SegmentConsumer consumer;

		SegmentConsumerTupel( SEGMENT aSegment, SegmentConsumer aConsumer ) {
			segment = aSegment;
			consumer = aConsumer;
		}

		void onSegment() {
			consumer.onSegment( segment );
		}
	}

	private static class RequestHandlerTupel {

		REQUEST request;
		RequestHandler handler;

		RequestHandlerTupel( REQUEST aRequest, RequestHandler aHandler ) {
			request = aRequest;
			handler = aHandler;
		}

		public Segment onRequest() {
			return handler.onRequest( request );
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public String toString() {
			return getClass().getSimpleName() + " [request=" + request + ", handler=" + handler + "]";
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy